I'm wondering how I can manipulate the size of strip text in facetted plots. My question
is similar to a question on plot titles, but I'm specifically concerned with
manipulating not the plot title but the text that appears in facet titles (strip_h).
As an example, consider the mpg dataset.
library(ggplot2)
qplot(hwy, cty, data = mpg) + facet_grid( . ~ manufacturer)
The resulting output produces some facet titles that don't fit in the strip.
I'm thinking there must be a way to use grid to deal with the strip text. But I'm
still a novice and wasn't sure from the grid appendix in Hadley's book how,
precisely, to do it.
You can modify strip.text.x (or strip.text.y) using theme_text(), for instance
qplot(hwy, cty, data = mpg) +
facet_grid(. ~ manufacturer) +
opts(strip.text.x = theme_text(size = 8, colour = "red", angle = 90))
Update: for ggplot2 version > 0.9.1
qplot(hwy, cty, data = mpg) +
facet_grid(. ~ manufacturer) +
theme(strip.text.x = element_text(size = 8, colour = "red", angle = 90))
Nowadays the usage of opts and theme_text seems to be deprecated. R suggests to use theme and element_text. A solution to the answer can be found here: http://wiki.stdout.org/rcookbook/Graphs/Facets%20%28ggplot2%29/#modifying-facet-label-text
qplot(hwy, cty, data = mpg) +
facet_grid(. ~ manufacturer) +
theme(strip.text.x = element_text(size = 8, colour = "red", angle = 90))
I guess in the example of mpg changing the rotation angle and font size is fine, but in many cases you might find yourself with variables that have quite lengthy labels, and it can become a pain in the neck (literally) to try read rotated lengthy labels.
So in addition (or complement) to changing angles and sizes, I usually reformat the labels of the factors that define the facet_grid whenever they can be split in a way that makes sense.
Typically if I have a dataset$variable with strings that looks like
c("median_something", "aggregated_average_x","error","something_else")
I simply do:
reformat <– function(x,lab="\n"){ sapply(x, function(c){ paste(unlist(strsplit(as.character(c) , split="_")),collapse=lab) }) }
[perhaps there are better definitions of reformat but at least this one works fine.]
dataset$variable <- factor(dataset$variable, labels=reformat(dataset$variable, lab='\n')
And upon facetting, all labels will be very readable:
ggplot(data=dataset, aes(x,y)) + geom_point() + facet_grid(. ~ variable)
Related
I'm attempting to write some code that can be used to make boxplots of temperatures at which proteins melt at, I'm 99% there except I need to introduce a line break on the y-axis of my boxplot.
Essentially, my current y axis scale goes from 45-60, I want to make the y axis start at 0, line break, 45-60. See the picture as an e.g.
I've tried using the scale_y_continuous to set a break but that didn't work as I'd hoped.
df %>%
group_by(Protein) %>%
ggplot(., aes(x = factor(Protein), y = Melting_Temperature)) +
geom_boxplot() +
theme_classic() +
geom_point(aes(x = as.numeric(df$Protein) + 0.5, colour = Protein),
alpha=0.7)+
xlab("Protein Type")+
ylab("Melting Temperature") +
stat_summary(fun.y=mean, colour = "darkred", geom = "point", shape =
18, size = 3, show_guide = FALSE) +
geom_text(data = means, aes(label = round(Melting_Temperature, 1), y =
Melting_Temperature + 0.5))
IMHO, tick marks and axis labels should be sufficient to indicate the range of data on display. So, there is no need to start an axis at 0 (except for bar charts and alike).
However, the package ggthemes offers Tufte style axes which might be an alternative to the solution the OP is asking for:
library(ggplot2)
library(ggthemes)
ggplot(iris) +
aes(x = Species, y = Sepal.Length) +
geom_boxplot() +
geom_rangeframe() +
theme_tufte(base_family = "")
Note that the iris dataset is used here in place of OP's data which are not available.
geom_rangeframe() plots axis lines which extend to the maximum and minimum of the plotted data. As the plot area is usually somewhat larger this creates a kind of gap.
theme_tufte() is a theme based on Chapter 6 "Data-Ink Maximization and Graphical Design" of Edward Tufte's The Visual Display of Quantitative Information with no border, no axis lines, and no grids.
This is not supported in ggplot as built. In this discussion from 2010, Hadley Wickham (author of ggplot as well as RStudio et al) explains that axis breaks are questionable practice in his view.
Those comments by Hadley are linked, and other options discussed, in this prior SO discussion.
I'm a newbie, so this might be super basic.
When I run this code
Dplot <- qplot(x = diamonds$carat, y = diamonds$price, color = diamonds$color) +
ggtitle("An A+ plot") +
xlab("carat") +
ylab("price") +
geom_point()
Dplot <- Dplot + facet_wrap(vars(diamonds$clarity))
Dplot
I get an error message that says:
Error in gList(list(x = 0.5, y = 0.5, width = 1, height = 1, just =
"centre", :
only 'grobs' allowed in "gList"
I've tried googling, but haven't been able to figure out what the issue is.
I would advise against using qplot except in the most basic cases. It teaches bad habits (like using $) that should be avoided in ggplot.
We can make the switch by passing the data frame diamonds to ggplot(), and putting the mappings inside aes() with just column names, not diamonds$. Then the facet_wrap works fine as long as we also omit the diamonds$:
Dplot = ggplot(diamonds, aes(x = carat, y = price, color = color)) +
ggtitle("An A+ plot") +
xlab("carat") +
ylab("price") +
geom_point()
Dplot + facet_wrap(vars(clarity))
Dplot + facet_wrap(~ clarity) # another option
Notice the code is actually shorter because we don't need to type diamonds$ all the time!
The vars(clarity) option works fine, more traditionally you would see formula interface used ~ clarity. The vars() option is new-ish, and will play a little nicer if you are writing a function where the name of a column to facet by is stored in a variable.
Problem
I have 4 graphs that I want to display using grid.arrange(). When I display them individually, they look like this:
But when I use grid.arrange(), they become distorted
with them individually looking like
Specific Issues:
The x-axis labels do not scale and overlap, making them unreadable.
The subtitles get cutoff.
Goal
I want to reproduce each plot exactly like the first ideal case in a grid with grid.arrange(). One possible way might be to convert each plot to an image and then use grid.arrange() but I don't know how to do this.
Reproducible Example
Below is an example reproducible code that shows the problem I am having.
p1 <- ggplot(subset(mtcars, cyl = 4), aes(wt, mpg, colour = cyl)) + geom_point() + labs(title = "TITLE-TITLE-TITLE-TITLE-TITLE-TITLE", subtitle = "-subtitle-subtitle-subtitle-subtitle-subtitle-subtitle-subtitle-") +theme(plot.title = element_text(hjust = 0.5),plot.subtitle = element_text(hjust = 0.5))
p2 <- ggplot(subset(mtcars, cyl = 4), aes(wt, mpg, colour = cyl)) + geom_point() + labs(title = "TITLE-TITLE-TITLE-TITLE-TITLE-TITLE", subtitle = "-subtitle-subtitle-subtitle-subtitle-subtitle-subtitle-subtitle-") +theme(plot.title = element_text(hjust = 0.5),plot.subtitle = element_text(hjust = 0.5))
grid.arrange(p1, p2, ncol = 2)
When you display those graphs individually they simply have more space. So, those are natural distortions and there are perhaps only three ways to solve that.
When exporting the combined graph, make it big enough. If the individual one looks good in 6x5 inches, then surely the combined one will look good in 12x10 inches.
Give correspondingly less space for the problematic parts: x-axis labels and the subtitle. For instance, use something like element_text(size = 6) for plot.subtitle and axis.title.x, add \n to the subtitles and even x-axis labels, try something like element_text(angle = 30) for the latter as well.
Get rid of something unnecessary. As #Richard Telford suggests in the comments, using facet_wrap should work better. That would be due to, e.g., not repeating the y-axis labels and, hence, giving more horizontal space.
I have created the plot below with these commands:
ggplot(long.data, aes(owner,value)) + stat_summary(fun.y=mean,geom="bar",
fill=c("deepskyblue","deepskyblue4")) +
stat_summary(fun.data=mean_cl_normal,geom="errorbar",position=
position_dodge(width=.90),width=.1) +
labs(x="",y="") + facet_grid(IV~experiment+type,scales="free_y") +
theme(strip.text.y = element_text(colour = 'red4'))
If I want to change the text color (and possibly also the background color) for only the upper x facet (in this case 'Implicit' and 'Explicit' levels), how can I do that? Is it possible? I have not read nothing about that in the ggplot2 documentation.
EDIT: I'm sorry for the confusion. My aim is to change the text and background color of one of the upper strips, not the color of the facet.
You want to change the attributes of the strip element, not the facet. Try something like the code below. Note that this is a minimal example based on fake data made up at random, as you did not provide your own data for us to work with. You'll have to adapt the code to your needs.
require(reshape)
require(ggplot2)
require(scales)
# fake data
mydf <- data.frame(val1 = runif(10, 0, 1), val2 = runif(10, 0, 1))
mydf
# reshape to long format
long.data <- melt(mydf)
long.data$facetvar <- "implicit"
long.data$facetvar[seq(1, 19, 2)] <- "explicit"
long.data
# plot
ggplot(long.data, aes(y = value, x = variable)) +
geom_bar(position = 'dodge', stat = "identity") +
facet_wrap (~ facetvar) +
theme(strip.background = element_rect(fill = alpha('green', 0.3))) +
theme(strip.text.x = element_text(colour = 'blue', size = 10))
This produces a plot like this:
Please note that you have waited quite a while (by the standards of the R community on Stack Overflow) for an answer because your question wasn't clear and because you didn't provide fully reproducible code and data that we can copy and paste into our own R installations. If you had done that, somebody far more knowledgeable than myself would have answered this question within an hour. Please see this very useful post for tips on how to ask your next question.
I get a warning... but this seems a good starting point for a more elegant solution:
ggplot(mtcars) + geom_rect(data = subset(mtcars, cyl == 4), aes(fill = cyl),xmin = -inf,xmax = Inf, ymin = -Inf,ymax = Inf, alpha = 0.05) +
geom_point(aes(mpg, wt)) + facet_grid(. ~ cyl)
I'd like to add a footnote citation to my 3-panel facet grid plot produced in R. It's a footnote to credit the data source. I'd ideally like to have it below and external to all three axes---preferably in the lower left.
I'm using ggplot2 and also ggsave(). This means I can't use grid.text()-based solutions, because that only draws on the x11() window, and can't be added to the ggplot object.
Using instead png() ...code... dev.off() does not appear to be an option because I need ggsave's resizing parameters, and find this command produces better, clearer prints (that are also much faster, because I'm not printing to the screen).
Here's my basic code:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
I've tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
grid.text(unit(0.1,"npc"),0.025,label = "Data courtesy of Me")
grid.gedit("GRID.text", gp=gpar(fontsize=7))
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This appropriately puts the footnote in the lower left corner on the x11() display, external to the plots, but unfortunately, since it isn't applied to the p1 object, it isn't saved by the ggsave command.
I've also tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle) +
annotate("text", label = "Footnote", x = 0, y = 10, size = 5, colour = "black") +
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This successfully prints using ggsave, however it has the following problems:
It is repeated 3 times, in each of the 3 facets, rather than 1 time.
It is contained within the plots, rather than external to them.
Text is difficult to place---seems to be using plot units (my x-axis is date, so 0 puts it around 1970).
The text size doesn't seem to change despite my size parameter.
A couple of related links from when I explored this...
ggplot2 footnote
(doesn't work with ggsave)
How to label the barplot in ggplot with the labels in another test result?
(is inside the plot, not external/below plot)
Different font faces and sizes within label text entries in ggplot2
(doesn't work with ggsave)
problem saving pdf file in R with ggplot2
ggplot2 now has this ability natively with no need for additional packages. ... + labs(caption = "footnote", ...)
library(ggplot2)
ggplot(diamonds, aes(carat, price, color = clarity)) +
geom_point() +
labs(title = "Diamonds are forever...",
subtitle = "Carat weight by Price",
caption = "H. Wickham. ggplot2: Elegant Graphics for Data Analysis Springer-Verlag New York, 2009.")
library(gridExtra)
library(grid)
library(ggplot2)
g <- grid.arrange(qplot(1:10, 1:10, colour=1:10) + labs(caption="ggplot2 caption"),
bottom = textGrob("grid caption", x = 1,
hjust = 1, gp = gpar(fontface = 3L, fontsize = 9)))
ggsave("plot.pdf", g)
Edit: note that this solution is somewhat complementary to the recent caption argument added to ggplot2, since the textGrob can here be aligned with respect to the whole figure, not just the plot panel.
Adding to the answer of Brandon Bertelsen: if you want to have the caption in the left corner, add
theme(plot.caption = element_text(hjust = 0))