Following a previous R post Specifying ggplot2 panel width, I have been able to produce this plot:
with this code.
You can find the output of dput(datos) at http://ubuntuone.com/0Nlb97mOeDhSbFrbFKCeEG
Now my question is how can I remove/reduce the white space between the graphs. I have found examples with ggExtra package, ggplot and facet, multiplots with options as plot.margin or panel.margin but couldn't find how to apply to my case.
Thanks for your help.
EDIT: I have just noticed that plots have not the same width. It is needed they have the same width so they can share x axis labels from bottom plot.
Using xlab(NULL) instead of xlab(" ") will remove some space off the bottom of each plot.
Using opts(plot.margin = unit(c(0,0,0,0), "cm")) will remove a little space from the edges.
I think that your have overcomplicated things by creating 5 separate graphs and recombining them. Faceting is much easier.
mdatos <- melt(datos[, -1], id.vars = "dia")
(p_all <- ggplot(mdatos, aes(dia, value)) +
geom_line(colour = "blue") +
facet_grid(variable ~ ., scale = "free_y") +
xlab("Day") +
ylab(NULL)
)
The plot panels aren't the same width because some y axis labels have three digit numbers, and some only two. Either change the formatting of the y axis, or use my facetting suggestion.
You can layout and control the margins of several subplots with par and layout. For example:
par (fig=c(0,1,0,1), # Figure region in the device display region (x1,x2,y1,y2)
omi=c(0,0,0.3,0), # global margins in inches (bottom, left, top, right)
mai=c(0.1,0.1,0.3,0.1)) # subplot margins in inches (bottom, left, top, right)
layout(matrix(1:4, 2, 2, byrow = TRUE))
Related
Using facet_grid(), how can I place the group names, i.e. the grey strips, on the top of the plots when graphing the plots stacked vertically in a single column?
From what I have tried, when stacking the plots vertically, using facet_grid(), you cannot place the strip on the top or bottom of the graph; you can only place the strip on the right hand side or the left hand side of the plots using the switch = c("y", "x", "both") argument.
I am aware that facet_wrap() (and facet_col() from ggforce) can place the strip anywhere using the strip.position = c("top", "bottom", "left", "right") argument, irrespective of how the graphs are being plotted: vertically or horizontally. I used facet_wrap() to produce Fig.1 below (code is in the Reproducible Code section).
However, I would like to be able to produce the plot below (with the strip on "top") using facet_grid() not facet_wrap.
Fig.1: I want to be able to plot this using facet_grid()
Ideally, it would be great if the switch argument could be extended or the strip.position argument could be added to facet_grid(), to be able to place the strip on top. I tried to do it myself by trying to change the source code from facet_grid() and facet_wrap() functions, but could not figure it out.
The reason I am not simply using facet_wrap() function is because it unfortunately does not have the space="free" argument which is available in facet_grid() and is essential in my application.
Below is a reproducible example taken from, with slight modifications, the code of Brandon Bertelsen answer's here:
Reproducible Code:
The Data:
dat <- data.frame(value=runif(30)*10,
grouping=c(rep("Group 1",10),
rep("Group 2",10),
rep("Group 3",10)),
letters=rep(LETTERS[1:10], 3)
Using facet_wrap to get strip on top when plotting graphs vertically:
ggplot(dat, aes(letters,value, label = letters)) +
geom_bar(stat="identity") +
facet_wrap(grouping~., dir = "v")
Produces Fig.1:
Using facet_grid with the switch = "y" places the strip to the left hand side:
ggplot(dat, aes(letters,value, label = letters)) +
geom_bar(stat="identity") +
facet_grid(grouping~., switch = "y")
Produces Fig.2:
Using facet_grid with the switch = "x" places the strip to the right hand side:
ggplot(dat, aes(letters,value, label = letters)) +
geom_bar(stat="identity") +
facet_grid(grouping~., switch = "x")
Produces Fig.3:
With no other options remaining I turn here for help.
Is that what you want? Then just leave sales = 'free' out.
library(ggplot2)
dat <- data.frame(value=runif(26)*10,
grouping=c(rep("Group 1",10),
rep("Group 2",10),
rep("Group 3",6)),
letters=LETTERS[1:26])
ggplot(dat, aes(letters,value, label = letters)) +
geom_bar(stat="identity") +
facet_wrap(grouping~., dir = "v")
Created on 2020-06-13 by the reprex package (v0.3.0)
I am trying to create a facet_grid() in ggplot() and am having issues with the margins of my plot. I am using grid.draw() for my final plot, and cannot figure out how to adjust the margins for printing. When I save my plot, it appears fine (see below). However, when I actually print my plot out to hard copy, half of the X&Y labels and my plot title are cut off.
I've attempted using par() to no avail. Here is a reproducible example, similar to my actual plot. I need to keep the panel <- off part because in my actual plot, I have plotted numbers above each bar and they get cut off by the facet sides for days at the beginning/end of each month. I'm thinking this might be the root of the issue, but I'm not really sure to be honest.
data(airquality)
library(stats)
library(ggplot2)
library(gtable)
library(gridExtra)
library(grid)
library(dplyr)
library(scales)
facet <- ggplot() +
geom_bar(data=airquality,aes(y=Wind,x=Day,fill=Temp),colour="black",stat="identity",position='stack') +
#theme_bw() +
facet_grid(~Month) +
theme(axis.title.x=element_text(face="bold",size=14),axis.title.y=element_text(face="bold",size=14),axis.text.x=element_text(face="bold",size=10),axis.text.y=element_text(face="bold",size=10))+
ylab("Wind") +
theme(panel.margin = unit(5, "mm"),panel.border=element_rect(color="black",fill=NA),panel.background = element_rect(fill="grey84"),plot.title = element_text (size=20,face="bold"),legend.position="right",panel.grid.minor=element_blank(),strip.text.x=element_text(size=12,face="bold"),strip.background=element_rect(fill=NA,colour="black"),legend.title=element_text(size=14,face="bold")) +
ggtitle("Test")
gt <- ggplot_gtable(ggplot_build(facet))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
Thanks for any and all help! Please, let me know if you need any clarification or have any questions.
you have two options:
set some margins in the ggplot theme
assign a viewport of specific size to the plot/gtable, smaller than the device window by some margin. Here's an illustration of using both strategies at once
library(grid)
fig_size <- c(6, 4) # inches
margin <- unit(4, "line")
p <- ggplot() + theme(plot.background=element_rect(colour="red", size=2, fill="grey50"),
plot.margin = unit(1:4, "line"))
g <- ggplotGrob(p)
g$vp <- viewport(width = unit(fig_size[1], "in") - margin, height=unit(fig_size[2],"in")- margin)
ggsave("plot.pdf", g, width=fig_size[1], height=fig_size[2])
To display multiple plots I use multiplot (http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/), now I have two plots who share the same x-axis range and are plotted above each other:
multiplot(plot1, plot2)
I removed the x-axis labels and title using:
xlab(NULL) + theme(axis.text.x=element_blank(),axis.ticks.x=element_blank())
But there is still a white margin between the two plots. How can I make this margin smaller or remove it?
To reduce space between the plots, remove the bottom margin of the top plot and remove the top margin of the bottom plot. The code below sets these margins to 0, which still results in a tiny bit of white space between the plots. You can make these margins slightly negative (maybe -0.1 or so) to completely remove the white space. Rather than the multiplot function, we use grid.arrange from the gridExtra package to lay out the plots. :
library(grid)
library(gridExtra)
## Create two sample plots with the same x axis using built-in mtcars data frame
# Top plot: Remove bottom margin, x-labels, and x title
p1 = ggplot(mtcars, aes(wt, mpg)) + geom_point() +
xlab(NULL) +
theme(axis.text.x=element_blank(),axis.ticks.x=element_blank(),
plot.margin=unit(c(1,1,0,1), "lines"))
# Bottom plot: Remove top margin
p2 = ggplot(mtcars, aes(wt, carb)) + geom_point() +
theme(plot.margin=unit(c(0,1,1,1), "lines"))
# Lay out plots in one column
grid.arrange(p1, p2, ncol=1)
Two problems with the above layout: (1) the y axes are not justified properly, and (2) the height of the lower plot's plot area is less than that of upper plot's plot area. The code below addresses these issues:
# Left justify plots
# Source: http://stackoverflow.com/a/13295880/496488
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
# Lay out justified plots. Use heights argument to equalize heights of each plot area
grid.arrange(gA, gB, heights=c(0.47,0.53), ncol=1)
You can exactly equalize the heights of each plot area using the same trick as we used to left-justify the plots (rather than doing it by eye using the heights argument to grid.arrange), but then the plot margins get added back. I'm not sure of how to deal with that, but here's the code for reference:
maxHeight = grid::unit.pmax(gA$heights[2:5], gB$heights[2:5])
gA$heights[2:5] <- as.list(maxHeight)
gB$heights[2:5] <- as.list(maxHeight)
The last update of ggplot2 gives much more control over the plot. See for example:
ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
facet_wrap(~vs)
You can further adjust the labels, number of rows, and how scales will be displayed, for instance: nrow = 2; scales = "free".
It is easier than you might think to re-arrange the data so that you can take advantage of the nice alignment features that already exist in ggplot2. See below for an example replicating eipi10's answer, but without having to use ggplotGrob.
What you have to do is just select the columns you want to plot, along with the ID columns (in this case, the car model and the x-axis value column). Then melt, and it's ready to plot using the standard facet procedure.
Note that the "switch" option in the facet_grid call is a new feature that you can access by updating to the most recent CRAN version. I used that to replace the regular y-axis title, which was omitted using theme.
The nice part about this approach is that the plots will always be perfectly aligned.
library("ggplot2")
library("dplyr")
library("reshape2")
df <- mtcars %>%
add_rownames(var = "Model") %>%
select(Model, wt, mpg, carb) %>%
melt(id.vars = c("Model","wt"))
ggplot(df)+
aes(x=wt, y=value)+
geom_point()+
theme(strip.background=element_blank())+
facet_grid(variable ~ ., scales="free_y", switch="y")
With the following code:
library(ggplot2)
set.seed(6809)
diamonds <- diamonds[sample(nrow(diamonds), 1000), ]
diamonds$cut <- factor(diamonds$cut,
levels = c("Ideal", "Very Good", "Fair", "Good", "Premium"))
# Repeat first example with new order
p <- ggplot(diamonds, aes(carat, ..density..)) +
geom_histogram(binwidth = 1)
p + facet_grid(color ~ cut)
I can create the following figure:
My questions are:
How can I sort the right strip according to my desired order
e.g. (G, F, D, E, I, J, H)?
How can I swap the right strip to with the y-axis (density)?
Update for ggplot2 2.2.1
With ggplot2 version 2, you can switch the positions of the axis labels and facet labels. So here's updated code that takes advantage of these features:
# Reorder factor levels
diamonds$color = factor(diamonds$color, levels=c("G","F","D","E","I","J","H"))
ggplot(diamonds, aes(carat, ..density..)) +
geom_histogram(binwidth=1) +
facet_grid(color ~ cut, switch="y") + # Put the y facet strips on the left
scale_y_continuous("density", position="right") + # Put the y-axis labels on the right
theme(strip.text.y=element_text(angle=180))
Original Answer
As #joran said, you have to modify the grid object if you want full control over what goes where. That's painful.
Here's another approach that's still a hassle, but easier (for me at least) than modifying the grid object. The basic idea is that we orient the various facet and axis labels so that we can rotate the plot 90 degrees counter-clockwise (to get the facet labels on the left side) while still having all the labels oriented properly.
To make this work, you need to modify the graph in several ways: Note my addition of coord_flip, all the theme stuff, and scale_x_reverse. Note also that I've switched the order of the facet variables, so that color starts out on top (it will be on the left after we rotate the graph).
# Reorder factor levels
diamonds$color = factor(diamonds$color, levels=rev(c("G","F","D","E","I","J","H")))
p <- ggplot(diamonds, aes(carat, ..density..)) +
geom_histogram(binwidth = 1) +
facet_grid(cut ~ color) + coord_flip() +
theme(strip.text.x=element_text(angle=-90),
axis.text.y=element_text(angle=-90, vjust=0.5, hjust=0.5),
axis.text.x=element_text(angle=-90, vjust=0.5, hjust=0),
axis.title.x=element_text(angle=180),
axis.title.y=element_text(angle=-90)) +
scale_x_reverse()
One option is to save the graph and then rotate it in another program (such as Preview, if you're on a Mac). However, with the help of this SO answer, I was able to rotate the plot within R. It required some trial and error (with my limited knowledge of how to manipulate grid objects) to get the right size for the viewport. I saved it as a PNG for posting on SO, but you can of course save it as a PDF, which will look nicer.
png("example.png", 500,600)
pushViewport(viewport(width = unit(8, "inches"), height = unit(7, "inches")))
print(p, vp=viewport(angle=90))
dev.off()
And here's the result:
facet_grid has the attribute "switch".
switch: By default, the labels are displayed on the top and right of the plot. If "x", the top labels will be displayed to the bottom. If "y", the right-hand side labels will be displayed to the left. Can also be set to "both".
manual here
facet_grid(cut ~ color, switch = "y")
I use ggplot2 and knitr to publish scatterplots with a right-hand-side legend. The legend is included in the aspect ratio and therefore breaks the "squareness" of the plots, as shown in the default themes. When the legend text becomes a bit longer than "a" and "b", the graphs become "long rectangles" instead of "squares".
I would like to keep the graphs "squared", and so would like to exclude the legend from the aspect ratio on my ggplot2 graphs. My .Rprofile has the following information to force ggplot2 to produce low-colour graphs with bigger text and more space around axis titles:
theme_set(theme_bw(16))
theme_update(
axis.title.y = element_text(angle = 90, vjust = -.25),
axis.title.x = element_text(vjust = -1),
plot.margin = unit(c(1,1,1,1), "cm")
)
Is there anything I can add here to exclude the legend from the aspect ratio? Manipulations with coord_equal and coord_fixed have failed so far, as have the fig.width and fig.height options. Thanks for your help!
Edit: working example removed, question answered below with full example code (sorry for the delay in approving the answer).
Setting coord_fixed() should do the trick:
library(ggplot2)
library(gridExtra) ## for grid.arrange()
## Create some data with one longer label
cars <- transform(mtcars,
cyl = factor(cyl, labels=c("4","6","8 is big")))
## Compute ratio needed to make the figure square
## (For a taller narrow plot, multiply ratio by number > 1;
## for a squatter plot, multiply it by number in the interval (0,1))
ratio <- with(cars, diff(range(mpg))/diff(range(wt)))
## Make plots with and without a legend
a <- ggplot(cars, aes(mpg, wt)) +
geom_point() + coord_fixed(ratio=ratio)
b <- ggplot(cars, aes(mpg, wt, color=cyl)) +
geom_point() + coord_fixed(ratio=ratio)
## Plot them to confirm that coord_fixed does fix the aspect ratio
grid.arrange(a,b, ncol=2)