Dropping y strip, but not x, from ggplot2 facet - r

I am using ggplot2 to create a 2D facet plot. I wish to drop the y-axis strip (because it is self-explanatory) but remove the x-axis strip (because it is not).
I found several examples about how to remove both strips, e.g. this. However, in every case, it was showing you how to get rid of all the labels. There is an example of how to remove the labels from one panel and not the other, but this seems more complicated than I imagine (hope) it actually is. (Also, when I copied and pasted the code, R did not recognize the "unit" command that appeared in the code fragment, though I see that this is addressed elsewhere.)
So, let's say I have the facet grid below, and I want to hide the grey strip for cut, but not color.
require(ggplot2)
pdf(file = sprintf("minimal.pdf"))
p <- ggplot(diamonds, aes(carat, price))
p <- p + geom_point()
p <- p + facet_grid(cut ~ color, scales="fixed")
print(p)
dev.off()
Adding the following line turns both strips white, and removes the characters from the y-strip (cut).
p <- p + theme(strip.text.y = element_blank(), strip.background = element_blank())
That's an improvement, but what I really want to do is keep the x-strip as it was, with the original grey background, but remove the y-strip. Manually adjusting the margins every time I resize the figure, as is done in one of the references, does not seem like a nice way to do it. I am wondering if there is a better way.

You can subset the gtable to remove the column you don't want
g <- ggplotGrob(p)
strips <- subset(g$layout, grepl("strip-right", g$layout$name))
library(grid)
grid.newpage()
grid.draw(g[,-unique(strips$r)])

Related

How to alter distances between plots in a 4 X 4 graph panel?

I am trying to create a graph panel with 8 graphs in total ( 4 x 4). Each graph corresponds to a different gene, whereby there are three lines ( one for control, one for UC disease and one for Crohns), representing the average change in expression comparing a first measurement and a second.
The code I am using to run each of the plots is;
s <- ggplot(X876, aes(x=Timepoint, y=value, group=Group)) +
geom_line(aes(color=Group), size=1)+
geom_point(aes(color=Group), size=2.5) +
labs(y="X876") + ylim(0.35, 0.55) +
theme_classic() +
scale_color_manual(values=c("darkmagenta", "deepskyblue4", "dimgrey"))
Using grid.arrange(l, m, n, o, p, q, r, s, nrow=4, nrow=4), creates a graph panel where the y axes names overlap.
I have seen on here about changing the plot margins via,
pl = replicate(3, ggplot(), FALSE)
grid.arrange(grobs = pl)
margin = theme(plot.margin = unit(c(2,2,2,2), "cm"))
grid.arrange(grobs = lapply(pl, "+", margin))
However, I am unsure how this can be applied to increase the vertical height between the plots on the top and bottom rows. For each of the graphs l, m, n, o, p, q, r, s do I need to include
+ theme(plot.margin=unit(c(t,r,b,l),"cm"))
and then run the grid.arrange(l, m, n, o, p, q, r, s, nrow=4, ncol=4)
Please could somebody suggest which values do I need to include for top (t), right(r), bottom (b), left(l) to only increase the distance (by about 3cms) between the top and bottom row? I am trying different values and I'm not getting a decent graph panel yet.
Thank-you
Probably the easiest way is to create your own theme based on the theme_classic theme and then modify the plotting margins (and anything else) the way that you prefer.
theme_new <- theme_classic() +
theme(plot.margin=unit(c(1,0,1,0), "cm")) # t,r,b,l
Then set the theme (will revert back to the default on starting a new R session).
theme_set(theme_new)
The alternative is to use grid.arrange and modify the margins using the grobs as you've already mentioned.
Once the panels have been arranged, you can then modify the top and bottom margins (or left and right) by specifying the vp argument of grid.arrange, which allows you to modify the viewport of multiple grobs on a single page. You can specify the height and width using the viewport function from the grid package.
For example, if you have a list of ggplot() grobs called g.list that contain your individual plots (l,m,n,o,p,q,r,s), then the following would reduce the height of the viewport by 90%, which effectively increases the top and bottom margins equally by 5%.
library(grid)
library(gridExtra)
grid.arrange(grobs = g.list, vp=viewport(height=0.9))
Without your data, I can't test it, especially to see if the y-axes labels overlap. And I don't know why you think increasing the top and bottom margins can solve that problem since the y-axes are, by default, on the left-hand side of the graph.
Anyway, I'll use the txhousing dataset from the ggplot2 package to see if I can reproduce your problem.
library(ggplot2)
data(txhousing)
theme_new <- theme_classic() +
theme(plot.margin=unit(c(0.1,0.1,0.1,0.1), "cm"), text=element_text(size=8))
theme_set(theme_new)
tx.list <- split(txhousing, txhousing$year)
g.list <- lapply(tx.list, function(data)
{
ggplot(data, aes(x=listings, y=sales)) +
geom_point(size=0.5)
} )
grid.arrange(grobs = g.list, vp=viewport(height=0.9))
I don't see any overlapping. And I don't see why increasing the top and bottom margins would make much difference.
The question was asked a couple of years ago, but I bumped into it only now and thought that I might share a quick and dirty tip for this, which works good enough in many cases.
In some situations the theme is already so complex that this trick might be the easiest way: adding a few \n's (newlines) to the x and y axis names, as this will affect the distances between the plots in the panel. I've learned this trick for a slightly different purpose from here (originally from here).
I'll use the same logic for the example dataset (in this case: Orange from R built-in data sets) as in the excellent code by the previous answerer.
library(ggplot2)
library(gridExtra)
or.list <- split(Orange, Orange$Tree)
g.list <- lapply(or.list, function(data)
{
ggplot(data, aes(x=age, y=circumference)) +
theme_classic() +
geom_point(size=0.5) +
scale_x_continuous(name = "Age\n\n") +
scale_y_continuous(name = "\n\n\nCircumference")
} )
grid.arrange(grobs = g.list)

ggplot2 + scatterplot + geom_path

Do you know how to get the curved effect Jake Kaupp achieves on his plot?
Looks to be something along the lines of:
ggplot(full_data, aes(y = total_consumption_lbs, x = milk_production_lbs)) +
geom_xspline2(aes(s_open = TRUE, s_shape = 0.5))
Where geom_xspline2() comes from library(ggalt)
But don't ask me, here is his source code:
https://github.com/jkaupp/tidytuesdays/blob/master/2019/week5/R/analysis.R
This approach doesn't look quite as nice as your example, but it's a start, and some fiddling may get you the rest of the way.
First, some data to work with:
x <- seq(1:20)
y <- jitter(x,amount=1.5)
df <- data.frame(x,y)
The approach using ggplot2 is to draw a geom_smooth with very small span (small enough to cause lots of errors, as you'll see), and then plot points with white borders over the top of that.
ggplot(df, aes(x,y)) +
geom_smooth(se=F, colour="black", span=0.15) +
geom_point(fill="black", colour="white", shape=21, size=2.5) +
theme_minimal()
The downsides: As I noted above, you'll see many errors about singularities in the loess fit, because the span is so small. Second, you'll note that not all of the points are centred on the line, which makes sense since you are using a loess fit for the line. Lastly, there doesn't appear to be a way to change the width of the line around the points, so you end up with quite a thin white border.

change font size of labels without knowing labels in ggplot2

I would like to change the font size of the labels in this plot:
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
p
My problem: I do not know what the labels are. (I stored a plot in which I used different data.frame()s to add geom_text(). I now only loaded the plot (p in this example), but do not want to also load the data.frame()s with which I created the labels).
As I do not know what the labels are, I cannot use this solution:
p + geom_text(label=rownames(mtcars), size=2)
(Another problem with this solution would be that I still needed to delete the original geom_text() with the larger font-size).
I can change the size of all text in the plot with this solution:
library(grid)
grid.force()
grid.gedit("GRID.text", grep=TRUE, gp=gpar(fontsize=4.5))
However, now also my axes changed, which is not what I wanted.
I believe there are several options to achieve what I want, at least two of which should be fairly simply to implement:
Save the object from grid.gedit() to p1 and then p1 + theme(text = element_text(size=2)). My problem here: I do not know how to save the object from grid.gedit(). This would be my preferred option.
Go to the right viewport before applying grid.gedit(). I tried this, but still change both the labels (which I want) and the axes text (which I do not want).
Somehow extract the data.frame for the labels from the stored plot (p in this example) to apply the solution that I provided first.
You can inspect (/modify) the plot after building it,
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
g <- ggplot_build(p)
# original data is in str(g$plot$data)
# but it's easier to process the data for rendering
g[["data"]][[1]][["size"]] <- 5
g[["data"]][[1]][["colour"]] <- "red"
gg <- ggplot_gtable(g)
grid.newpage()
grid.draw(gg)
Your grid.gedit command was close. You need to set up a gPath so that the edit command finds just those labels in the plot panel. grid.ls(grid.force()) returns a hierarchy of grobs. Find the 'panel', then the 'text'. (Note: the 'g' in 'gedit' stands for 'grep = TRUE, global = TRUE')
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
p
library(grid)
grid.ls(grid.force()) # Locate the path to the labels in the panel
grid.gedit(gPath("panel","GRID.text"), gp=gpar(fontsize=4.5))
If you prefer, with a few more lines of code, the plot object can be edited rather than editing on screen.
g = ggplotGrob(p)
g = editGrob(grid.force(g), gPath("panel", "GRID.text"), grep=TRUE, gp=gpar(fontsize=4.5))
grid.newpage()
grid.draw(g)

Removing all colors from a ggplot2 linechart

Working with RStudio 0.98.1103, I am creating two versions of exactly the same graph: One with colors and one without. Since both graphs are exactly the same (apart from the coloring) I want to avoid typing nearly the same commands again. Hence, I create the colored plot, save it, manipulate it to make it black-grey-white and save the reduced version:
library(ggplot2)
bp <- ggplot(data=PlantGrowth, aes(x=group, y=weight)) +
geom_line(aes(color=group)) + theme(legend.position="none")
bp_bw <- bp + theme_bw() +
geom_line() + theme(legend.position="none")
ggsave("bp_bw.png", bp_bw)
Although bp looks quite normal, bp_bw doesn't. There is still a blury color shining behind the black bars (red - green - blue):
Closeup:
How can I get rid of this colors, i.e. remove all color completely from bp? Only restriction: I have to create the colored graphs first (although of course a different order would work).
I think a better solution is to create a base and only add the coloring part when needed:
bp <- ggplot(data=PlantGrowth, aes(x=group, y=weight)) +
theme_bw() + theme(legend.position="none")
bp_col <- bp + geom_line(aes(color=group))
bp_bw <- bp + geom_line()
This (more-or-less) makes sense. Your bp_bw code doesn't get rid of the old colored lines, it just adds black lines on top. Anti-aliasing as the image is displayed/saved lets some of the color through on the edges.
My recommendation is to modify the color scale rather than overplot black on top:
bp_bw2 = bp + scale_color_manual(values = rep("black", 20)) + theme_bw()
This will change the colors to all black rather than plotting black on top of colors. The rep("black", 20) is kind of a hack. Apparently values aren't recycled by scale_color_manual, but extra values aren't used so you need to give it a vector at least as long as the number of colors.
This also has the advantage of not needing to repeat the geom call, and if you had previously defined a color scale this will overwrite it. If you want to be more general you could also add a scale_fill_manual(), and you probably want to specify guide = FALSE so that you don't get a very unhelpful legend.
You also might want to check out scale_colour_grey, just because it's B&W doesn't mean all the colors have to be the same.

How to add a shared x-axis and legend to ggplot (arrangegrob) and avoid different sized figures?

I,m trying to get these figures together in one figure, but I would like to have a shared x-axis below all 3, without the last figure to have a different size than the other 2. Similar for the middle figure with the legend, I would like the legend to be outide the 6 figure, without affecting the size of one of the figures.
I use arrangeGrob(plot1, plot2, ...., plot6) right now.
If anyone has a sollution, please let me know.
Thank you in advance!
use ggplot::facet_grid to share the axis and gridExtra::grid.arrange to plot them side by side
data(mtcars)
require(ggplot2)
require(gridExtra)
p1 <- ggplot(mtcars, aes(x = factor(vs), y = mpg)) +
geom_boxplot() +
facet_grid(cyl~.)
# Hope that i understood your question about the legend correctly
p2 <- ggplot(mtcars, aes(x = gear, y = mpg, col = factor(vs))) +
geom_point() +
facet_grid(cyl~.)
grid.arrange(p1,p2, nrow=1)
This is how far I got this time. The figure are indeed similar within each row. However, I would like all the six graphs to be the same size, but it is difficult due to fact that the left 3 need a legend and "long" x-axis labels. The right panel is just the way I would like it for both panels and with that the x-labels and legend outside of the box.
For example the graph below with the legend (pasted on the right side) and x-labels added to it, without changing the figures size or at least cause no differences between figure sizes

Resources