I have a really simple question, which I am struggling to find the answer to. I hoped someone here might be able to help me.
An example dataframe is presented below:
a <- c(1:10)
b <- c(10:1)
df <- data.frame(a,b)
library(ggplot2)
g = ggplot(data=df) + geom_point(aes(x=a, y=b)) +
xlab("x axis")
g
I just want to learn how I change the text size of the axes titles and the axes labels.
You can change axis text and label size with arguments axis.text= and axis.title= in function theme(). If you need, for example, change only x axis title size, then use axis.title.x=.
g+theme(axis.text=element_text(size=12),
axis.title=element_text(size=14,face="bold"))
There is good examples about setting of different theme() parameters in ggplot2 page.
I think a better way to do this is to change the base_size argument. It will increase the text sizes consistently.
g + theme_grey(base_size = 22)
As seen here.
If you are creating many graphs, you could be tired of typing for each graph the lines of code controlling for the size of the titles and texts. What I typically do is creating an object (of class "theme" "gg") that defines the desired theme characteristics. You can do that at the beginning of your code.
My_Theme = theme(
axis.title.x = element_text(size = 16),
axis.text.x = element_text(size = 14),
axis.title.y = element_text(size = 16))
Next, all you will have to do is adding My_Theme to your graphs.
g + My_Theme
if you have another graph, g1, just write:
g1 + My_Theme
and so on.
To change the size of (almost) all text elements, in one place, and synchronously, rel() is quite efficient:
g+theme(text = element_text(size=rel(3.5))
You might want to tweak the number a bit, to get the optimum result. It sets both the horizontal and vertical axis labels and titles, and other text elements, on the same scale. One exception is faceted grids' titles which must be manually set to the same value, for example if both x and y facets are used in a graph:
theme(text = element_text(size=rel(3.5)),
strip.text.x = element_text(size=rel(3.5)),
strip.text.y = element_text(size=rel(3.5)))
Related
I've created a correlation matrix:
cor_matrix = cor(qual_colleges_all_data_clean[ ,c(4,5,8,9,10,12,13,14,16,20,21,22,23,25)], method='pearson',use='complete.obs')
ggcorrplot(cor_matrix, hc.order = TRUE, method ='circle', type='lower', colors = c("darkblue", "white", "red")) +
labs(title = "Correlation Matrix:", subtitle = "Select Variables") +
theme_minimal() +
theme(
legend.key.width = unit(0.6, "cm"),
legend.key.height = unit(1.3, "cm"),
axis.text.x = element_text(angle = 45) #to put x-axis labels at 45 angles
)
Here's what it looks like:
Initially the x-axis labels were all horizontal and thus were a jumbled mess, so I angled them. But as you can see, they're overlapping the plot. The problem is that I need to preserve theme_minimal() if at all possible. I've tried every theme() adjustment I could find online, but I cannot make anything work. So, I have three questions:
How can adjust the x-axis headings while preserving theme_minimal()?
How can I widen the plot while preserving theme_minimal()? My hope is that will space the circles a bit more suitably.
How can I eliminate the Var2 and Var1 axis labels while preserving theme_minimal()?
I realize these are basic questions, so I really appreciate you taking the time to help me. Thanks in advance!
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 am creating a number of plots using ggplot2 in R and want a way to standardize implementation of a cutoff line. I have data on a number of different measures for four cities over a ~10 year time period. I've plotted them as line graphs with each city a different color within a given graph. I will be creating a plot for each of the different measures I have (around 20).
On each of these graphs, I need to put two cutoff lines (with a word next to them) representing implementation of some policy so that people reading the graphs can easily identify the difference between performance before and after the implementation. Below is approximately the code I'm currently using.
gg_plot1<- ggplot(data=ggdata, aes(x=Year, y=measure1, group=Area, color=Area)) +
geom_vline(xintercept=2011, color="#EE0000") +
geom_text(aes(x=2011, label="City1\n", y=0.855), color="#EE0000", angle=90, hjust=0, family="serif") +
geom_vline(xintercept=2007, color="#000099") +
geom_text(aes(x=2007, label="City2", y=0.855), color="#000099", angle=0, hjust=1, family="serif") +
geom_line(size=.75) +
geom_point(size=1.5) +
scale_y_continuous(breaks=round(seq(min(ggdata$measure1, na.rm=T), max(ggdata$measure1, na.rm=T), by=0.01), 2)) +
scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
theme(axis.text.x = element_text(angle=90, vjust=1),
panel.background = element_rect(fill="white", color="white"),
panel.grid.major = element_line(color="grey95"),
text = element_text(size=11, family="serif"))
The problem with this implementation is that it relies on placing the two geom_text() on a particular place on the specific graph. These different measures all have different ranges so in order to do this I'd need to go plot by plot and find a spot to place them. What I'd prefer to do is something like force the range of each plot down by X% and put the geom_text() aligned to the bottom of the range. The lines shouldn't need adjusting (same year in every plot), just the position of the text. I found some similar questions here but none that had to do with the specific problem of placing something in the same position on different graphs with different ranges.
Is there a way to do what I'm looking for? If I had to guess, it'd something like using relative positioning rather than absolute but I haven't been able to find away to do that within ggplot. For the record, I'm aware the two geom_text()s are oriented differently. I did that to compare which we prefered but left it for you all. We will ultimately be going with the one that has the text rotated 90deg. Additionally, some of these will be faceted together so that might provide an extra layer of difficulty. Haven't gotten to that point yet.
Sidebar: an alternative way to visualize this would be to change the line from solid to dotted at the cutoff year. Is this possible? I'm not sure the client would want that but I'd love to present it as an option if anyone can point me in the direction of where to learn about how to do that.
Edit to add:
Sample data which shows what happens when running it with different y-ranges
ggdata <- data.frame(Area=rep(c("City1", "City2", "City3", "City4"), times=7),
Year=c(rep(2006,4), rep(2007,4), rep(2008,4), rep(2009,4), rep(2010,4), rep(2011,4), rep(2012,4)),
measure1=rnorm(28,10,2),
measure2=rnorm(28,50,10))
Sample plot which has the geom_text()s in the proper position, but this was done using the code above with a fixed position within the plot. When I replicate the code using a different measure that has a differnet y-range it ends up stretching the plot window.
You can use the y-range of the data to position to the text labels. I've set the y-limits explicitly in the example below, but that's not absolutely necessary unless you want to change them from the defaults. You can also adjust the x-position of the text labels using the x-range of the data. The code below will position the labels at the bottom of the plot, regardless of the y-range of the data.
I've also switched from geom_text to annotate. geom_text overplots the text labels multiple times, once for each row in the data. annotate plots the label once.
ypos = min(ggdata$measure1) + 0.005*diff(range(ggdata$measure1))
xv = 0.02
xh = 0.01
xadj = diff(range(ggdata$Year))
ggplot(data=ggdata, aes(x=Year, y=measure1, group=Area, color=Area)) +
geom_vline(xintercept=2011, color="#EE0000") +
geom_vline(xintercept=2007, color="#000099") +
geom_line(size=.75) +
geom_point(size=1.5) +
annotate(geom="text", x=2011 - xv*xadj, label="City1", y=ypos, color="#EE0000", angle=90, hjust=0, family="serif") +
annotate(geom="text", x=2007 - xh*xadj, label="City2", y=ypos, color="#000099", angle=0, hjust=1, family="serif") +
scale_y_continuous(limits=range(ggdata$measure1),
breaks=round(seq(min(ggdata$measure1, na.rm=T), max(ggdata$measure1, na.rm=T), by=1), 0)) +
scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
theme(axis.text.x = element_text(angle=90, vjust=1),
panel.background = element_rect(fill="white", color="white"),
panel.grid.major = element_line(color="grey95"),
text = element_text(size=11, family="serif"))
UPDATE: To respond to your comment, here's how you can create a separate plot for each "measure" column in your data frame.
First, we create reproducible data with three measure columns:
library(ggplot2)
library(gridExtra)
library(scales)
set.seed(4)
ggdata <- data.frame(Year=rep(2006:2012,each=4),
Area=rep(paste0("City",1:4), 7),
measure1=rnorm(28,10,2),
measure2=rnorm(28,50,10),
measure3=rnorm(28,-50,5))
Now, we take the code from above and package it in a function. The function take an argument called measure_var. This is the data column, provided as a character_string, that will provide the y-values for the plot. Note that we now use aes_string instead of aes inside ggplot.
plot_func = function(measure_var) {
ypos = min(ggdata[ , measure_var]) + 0.005*diff(range(ggdata[ , measure_var]))
xv = 0.02
xh = 0.01
xadj = diff(range(ggdata$Year))
ggplot(data=ggdata, aes_string(x="Year", y=measure_var, group="Area", color="Area")) +
geom_vline(xintercept=2011, color="#EE0000") +
geom_vline(xintercept=2007, color="#000099") +
geom_line(size=.75) +
geom_point(size=1.5) +
annotate(geom="text", x=2011 - xv*xadj, label="City1", y=ypos,
color="#EE0000", angle=90, hjust=0, family="serif") +
annotate(geom="text", x=2007 - xh*xadj, label="City2", y=ypos,
color="#000099", angle=0, hjust=1, family="serif") +
scale_y_continuous(limits=range(ggdata[ , measure_var]),
breaks=pretty_breaks(5)) +
scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
theme(axis.text.x = element_text(angle=90, vjust=1),
panel.background = element_rect(fill="white", color="white"),
panel.grid.major = element_line(color="grey95"),
text = element_text(size=11, family="serif")) +
ggtitle(paste("Plot of", measure_var))
}
We can now run the function once like this: plot_func("measure1"). However, let's run it on all the measure columns in one go by using lapply. We give lapply a vector with the names of the measure columns (names(ggdata)[grepl("measure", names(ggdata))]), and it runs plot_func on each of these columns in turn, storing the resulting plots in the list plot_list.
plot_list = lapply(names(ggdata)[grepl("measure", names(ggdata))], plot_func)
Now if we wish, we can lay them all out together using grid.arrange. In this case, we only need one legend, rather than a separate legend for each plot, so we extract the legend as a separate graphical object and lay it out beside the three plots.
# Function to get legend from a ggplot as a separate graphical object
# Source: https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs/047381b48b0f0ef51a174286a595817f01a0dfad
g_legend<-function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)
}
# Get legend
leg = g_legend(plot_list[[1]])
# Lay out all of the plots together with a single legend
grid.arrange(arrangeGrob(grobs=lapply(plot_list, function(x) x + guides(colour=FALSE))),
leg,
ncol=2, widths=c(10,1))
I am trying to plot a heat map with ggplot2 and I would like to resize the colorbar and increase the font.
Here is the relevant part of the code:
g <- ggplot(data=melt.m)
g2 <- g+geom_rect(aes(xmin=colInd-1, xmax=colInd,
ymin=rowInd-1, ymax=rowInd, fill=value))
g2 <- g2+scale_x_continuous('beta', breaks=c(1, ceiling(cols/2), rows)-0.5,
labels=c(1,ceiling(cols/2), rows))
g2 <- g2+scale_y_continuous('alpha', breaks=c(1, ceiling(rows/2), rows)-0.5,
labels=c(1, ceiling(rows/2), rows))
g2 <- g2+opts(panel.grid.minor=theme_line(colour=NA),
panel.grid.major=theme_line(colour=NA),
panel.background=theme_rect(fill=NA, colour=NA),
axis.text.x=theme_text(size=30),
axis.text.y=theme_text(size=30, angle=90),
axis.title.x=theme_text(size=30),
axis.title.y=theme_text(size=30, angle=90), title = title)
heatscale <- c(low='ghostwhite', high='steelblue')
g2 <- g2+scale_fill_gradient("", heatscale[1], heatscale[2], bias = 10)
It works fine, the problem is that the color legend on the right side is too small. Is there a way to make the color legend bigger and increase the font size of the legend?
Thanks,
kz
We don't have your melt.m data, so the code you give is not reproducible. Using the diamonds dataset that comes with ggplot2 as an example, though:
ggplot(diamonds, aes(x=table, y=price)) +
geom_bin2d() +
scale_fill_gradient("", 'ghostwhite', 'steelblue', bias=10) +
opts(legend.key.width=unit(1, "in"),
legend.text = theme_text(size=30))
legend.key.width and legend.text are what you are looking for. I have used exaggerated sizes to make it more obvious.
For more details on the options available, see https://github.com/hadley/ggplot2/wiki/+opts%28%29-List
I tried this and found that R or ggplot2 have changed in the last four years. It yielded the error:
Error: 'opts' is deprecated. Use 'theme' instead. (Defunct; last used in version 0.9.1)
Was able to get it to work with the following instead:
p + theme(legend.text = element_text(size=30),legend.key.size = unit(1, "in"))
Initially tried just changing the text size but had to change the key size with it or it becomes unreadable. Also, unit needs a library explicitly loaded with library(grid)
I am quite new to ggplot2, so forgive me if this post is too stupid.
I used the following code to plot the data, but I am not able to get the style that I need for publication.
In the output, I need:
a legend. In my data case, there is nothing after opts(legend.position="top") I have no idea why. And I also would like to split the legend into 3 columns like columns=3 in auto.key of lattice
Colorize the bars using grey system (eg, fill=c("white","grey20","grey70"))according to factor pl, but it seems that I cannot change the style with scale_colour_manual
turn around the labels on the x-axis into horizontal.
maybe a y-axis? But,do you think it is necessary?
BTW, I have no idea how to prepare a figure for publication, so, any suggestion is very welcome!
library(ggplot2)
wt<-gl(3,4,108,labels=c("W30","W60","W90"))
pl<-gl(3,12,108,labels=c("P0","P1","P2"))
gp<-gl(3,36,108,labels=c("A","B","C"))
dat<-cbind(A=runif(108),B=runif(108,min=1,max=10),C=runif(108,min=100,max=200),D=runif(108,min=1000,max=1500))
dat.df<-data.frame(wt,pl,gp,dat)
dat.m<-melt(dat.df)
ggplot(dat.m,aes(x=wt,y=value,group=pl,facet=gp,fill=pl))+
stat_summary(fun.y=mean,geom="bar",size=2,position="dodge")+
stat_summary(fun.ymin=function(x)(mean(x)-sd(x)/sqrt(length(x))),geom="errorbar",
fun.ymax=function(x)(mean(x)+sd(x)/sqrt(length(x))),position="dodge")+
facet_grid(variable~facet,scale="free_y")+ opts(legend.position="top")+
scale_colour_manual(values = c("red", "blue", "green"))
Here are some pointers:
To get a horizontal legend, use opts(legend.direction="horizontal")
To change the fill of the bars, you have to specify scale_fill_manual(values=c("white", "grey20", "grey70")). In your example, you have correctly mapped fill to pl. The only missing step is to map the manual scale to fill, rather than colour. Colour generally refers to the outline of the bar, and fill refers to the inside of the bar.
To rotate the angle of axis text, use opts(axis.text.x = theme_text(angle=45)). The default orientation is horizontal, so I use 45 degrees for illustration.
I don't know what you mean by "maybe a y-axis". Perhaps you don't want to display the y-axis, in which case you can suppress it by opts(axis.title.y = theme_blank())
Note that your example was not reproducible, so I had to invent some data. You can make it easier for us to respond if you ensure your example is reproducible:
There is no data for year
There is a reference to trt in your data.frame
You set up data for grp but then refer to it as gp
My code:
dat.df <- data.frame(
gp = gl(3, 36, 108, labels=c("A", "B", "C")),
yr = sample(2000:2010, 108, replace=TRUE),
A=runif(108),
B=runif(108, min=1, max=10),
C=runif(108, min=100, max=200),
D=runif(108, min=1000, max=1500)
)
dat.m <- melt(dat.df)
ggplot(dat.m, aes(x=wt, y=value, group=pl, facet=gp, fill=pl))+
stat_summary(fun.y=mean, geom="bar", size=2, position="dodge")+
stat_summary(fun.ymin=function(x)(mean(x)-sd(x)/sqrt(length(x))), geom="errorbar",
fun.ymax=function(x)(mean(x)+sd(x)/sqrt(length(x))), position="dodge")+#, position="dodge"
facet_grid(variable~facet, scale="free_y")+
scale_fill_manual(values=c("white", "grey20", "grey70")) +
opts(
legend.position="top",
legend.direction="horizontal",
axis.text.x = theme_text(angle=45),
axis.title.y = theme_blank()
)