Remove white space (i.e., margins) ggplot2 in R - r

I'm trying to plot a pie chart using GGPLOT2 in R. I want to do this in such a way as to omit the extra margin space.
What I'm doing is similar to what sharoz did in this post here except I want to include a legend.
Here is what I'm doing:
ggplot(DATA, aes(x=factor(0),fill=factor(LABELS),weight=VALUES)) +
geom_bar(width=1) +
coord_polar(theta='y') +
guides(fill=guide_legend(title='LEGEND'))

Assuming you are talking about the extra white space above and below the figure, the easiest solution is just to tweak the size of the graphics device. Here is aspect ratio is the key. If the aspect ratio of the graphics device matches that of the plot, you get rid of a lot of the whitespace.
What I use to save the plot is ggsave, in code:
ggplot(DATA, aes(x=factor(0),fill=factor(LABELS),weight=VALUES)) +
geom_bar(width=1) +
coord_polar(theta='y') +
guides(fill=guide_legend(title='LEGEND'))
ggsave("plot.png", width = 10, height = 5)
Just play around with width and height in ggsave until you are happy with the result.

Related

Arrange list of ggplot plots and adjust spacing/margin

I have a function that creates a list of ggplot plots. I'm currently using patchwork to arrange the plots together in a way that I can knit to Word, but I'm having a hard time with the way it looks when it renders. The output currently looks like this:
I'd like to make it so that it looks like this:
Currently, my code is the following:
patchwork_plots <- Reduce(`+`, plots)
patchwork_plots +
plot_layout(ncol=2)
I've tried a few different packages and different ways of adjusting, but nothing really seems to work. Any suggestions would be great.
A simple solution is to just change your aspect ratio and width= and height= of the plot. The graphics in your plots will not scale the same as the text in the plot, but will depend on the resolution and size/aspect ratio of your graphics device. Here is an example that shows 3 very different-looking plots that can result from adjusting the aspect ratio of your output.
library(ggplot2)
# intentionally crowded plot
gplot(mtcars, aes(mpg, disp)) + geom_point() +
facet_wrap(factor(cyl)~factor(carb), scales='free') +
labs(x='mpg is here and this is long', y='disp is here and this is long too!')
Width = 4, Height = 3
ggsave('plot4_3.png', width=4, height=3)
Width = 8, Height = 5
ggsave('plot8_5.png', width=8, height=5)
Width = 12, Height = 9
ggsave('plot12_9.png', width=12, height=9)

Adjust bin width with geom_col()

I'm having a trouble with the binwidth of my col graphics.
I'm trying to show the highest/lowest suicide rate by country on the same page using shiny.
But, the country names are overlaping one another as you can see below:
How can i adjust this?
There are quite a few possibilities for resizing and adjusting things so that your long axis labels "fit" on a column plot (or any other ggplot for that matter). I'll go through some options here.
First of all... a sample dataset, since we did not get a suitable reprex from your question.
df <- data.frame(
x=c('Text1', 'Text2', 'Long Text Here', 'Really Really Long Text Label Here', 'Text5', 'Text6', 'Text7'),
y=c(sample(1:20, 7, replace=TRUE)))
df$x <- factor(df$x, levels=df$x) # making sure ggplot doesn't alphabetically sort!
library(ggplot2)
p <- ggplot(df, aes(x,y)) +
geom_col(aes(fill=x), show.legend = FALSE)
p
There's your overlapping labels. Now for some options:
Option #1: Resize the plot
One very simple method to "solving" the problem is to realize that R handles graphics... kind of funny. The look of a particular plot depends on the resolution and aspect ratio of the graphics device. Not only that, but text does not scale the same as the other plot elements. This means that you can fix the problem by forcing a different aspect ratio.
# this was used to create the above plot
ggsave('original.png', width=8, height=5)
# changing the aspect ratio produces the plot below on my graphics device
ggsave('resized.png', width=12, height=5)
Option #2: Change the Text Size
The other option is to make your text size for the axis labels smaller. The result is really similar to just resizing the plot.
p + theme(axis.text.x=element_text(size=6))
Option #3: Angle the Text
One really good option is to angle your text using the theme() element again. Note that when you do this you want to change the default alignment of your labels. Set hjust=1 so that the text is "right aligned". If you are setting your angle to 90°, you will also want to set your vjust=0.5 to make the text aligned with the tick mark vertically. Here I'll show you a 45° angled text option:
p + theme(axis.text.x=element_text(angle=45, hjust=1))
Option #4: Wrap Text Labels
One of my go-to favorite options here is to wrap the text label. There are a few ways to do this, but I prefer using wrap_format() from the scales package and a scale_* function. Note, the number given to wrap_format(X) indicates that wrapping should happen after X number of characters in the label.
library(scales)
p + scale_x_discrete(labels=wrap_format(22))
Option #5: Combine all Above
The best way to fix your problem is to use a combination of all techniques above to get the chart to look the way you believe looks most satisfying. This will depend on how many columns you have in your shiny plot and how you generate that plot (user input or always the same, etc). So it's up to you here.
p + scale_x_discrete(name=NULL, labels=wrap_format(22)) +
scale_y_continuous(expand=expansion(mult=c(0,0.15))) +
theme_classic() + #important to put this before overwriting individual theme elements!
theme(
axis.text.x=element_text(angle=40, hjust=1, size=15),
axis.text.y=element_text(size=15),
panel.grid.major.y=element_line(color='gray75', linetype=2))
You can flip your graph horizontally, it will be better for the readers. You can add this to your graph to flip it:
coord_flip()

Draw geom_tile borders inside squares to prevent overlap

I would like to be able to draw borders on geom_tile that do not overlap so that borders can convey their own information without confusing the viewer with disappearing borders.
library(ggplot2)
state <- data.frame(p=runif(100), x=1:10, y=rep(1:10, each=10), z=rep(1:5, each=20))
ggplot(state, aes(x, y)) +
geom_tile(aes(fill = p, color=as.factor(z)), size=2)
I trust you can see how confusing overlapping borders can be.
Use the width and height arguments to geom_tile to create space and prevent border overlap.
ggplot(state, aes(x, y)) +
geom_tile(aes(fill = p, color=as.factor(z), width=0.7, height=0.7), size=2)
I've created space between the tiles, but you can also adjust the width and height so that the borders just touch each other. Also, note that in my version of the graph the color legend for tiles does not have any colors. This is because the border color legend for geom_tile is broken in ggplot2 2.0. The problem has been fixed in the development version of ggplot2, but the fix hasn't been rolled out to CRAN yet. To get the development version, you can do devtools::install_github("hadley/ggplot2").
(Incidentally, if you're into optical illusions, the graph below creates the grid illusion).

Expand plotting area by x-axis to make room for direct labels

I am polishing my graphs and have a problem with fitting direct labels in the plotting area. A want to remove most of the area between y1 and the y-axis to the left in the plot similar to that generated by the code below, but keep the extra area to the right to have room for the labels.
Adding +scale_x_discrete(expand=c(0,0.05)) removes extra area on both sides, but leaves no room for labels, and it can't seem to remove it on only one side.
Adding margins to the right of the plotting area with +theme(plot.margin = unit(c(0,4,0,0), "cm")) still doesn't allow the labels to appear there.
A solution that places the labels outside, to the right of the border would be even better.
Any help much appreciated.
library(ggplot2)
library(directlabels)
library(reshape2)
theme_set(theme_bw())
# some data
dfr<-data.frame(c("Longish Name A","Longish Name B","Longish Name C"),c(1,1,1),c(1,2,3),c(2,3,4))
colnames(dfr) <- c("subject","y1","y2","y3")
dfr<-melt(dfr, id.vars="subject")
# the graph
ggplot(data=dfr,aes(y=value, x=variable, group=subject)) +
geom_line(aes(color=subject))+
geom_dl(aes(label=subject), list(dl.trans(x=x+0.2), "last.qp", cex=0.5)) +
guides(color=FALSE)
Convert your x values to numeric inside the aes() and then use scale_x_continuous() to get back to original labels and set limits= that are wider on side.
ggplot(data=dfr,aes(y=value, x=as.numeric(variable), group=subject)) +
geom_line(aes(color=subject))+
geom_dl(aes(label=subject), list(dl.trans(x=x+0.2), "last.qp", cex=0.5)) +
guides(color=FALSE)+
scale_x_continuous(breaks=c(1,2,3),labels=c("y1","y2","y3"),expand=c(0,0.05),
limits=c(1,3.4))

Shrink y axis width

Is it possible to shrink y-axis? I mean instead of the plot being square, I want it to be rectangular, with y axis shrinked.
library(ggplot2)
data = data.frame(rnorm(10000))
colnames(data) = "numOfX"
m <- ggplot(data, aes(x=numOfX))
m + geom_histogram(colour = "blue", fill = "white", binwidth = 0.5)
last_plot() + opts(aspect.ratio=1/10)
You can adjust the margins by adding the following to the last line of your code:
+ opts(plot.margin = unit(c(1,1,10,1), "lines"))
The numbers are the number of lines to add to the margin in the order c(top, right, bottom, left).
Update: The methods that baptiste and I discussed will change the size of the plot itself, but not the size of the plot area. Just for completeness, if you want to change the aspect ratio of the plot but still have it fill the whole plot area, then you need to change the size of the plot area itself.
On the Mac you can do quartz(width=w, height=h), with width and height in inches. This will open a plot window of the specified size. Then run your original code (without margin or aspect ratio changes). This will give you whatever plot size you wish and the plot will fill the plotting area. You can use dev.off() to close the Quartz window when you're done with it.
You can do the same thing in Windows using this Stack Overflow answer.
Finally, if you're using RStudio, you can do Export-->Copy-to-Clipboard and then adjust the aspect ratio manually.
Of course, you can use a combination of my or baptiste's original answers along with the methods above to control both the size of the plot area and the size of the margins at the same time.

Resources