I'd like to vertically arrange my stacked geom_bar objects and display them with unbroken vertical lines (see concept below) and a single set of axes and legend. I'm using plot_grid now but should perhaps be using facet wrapping? I'm unsure whether that would allow me to place vertical lines. The code that generates my current plot is here.
my concept:
my current plot:
You could create your plots and disable the axis text, line and ticks. Then make the axis titles match the background color so they are not visible (but retain the same graph dimensions) and plot them with plot_grid() as you are doing. Then overlay a full sized plot with zero data, the axis titles and vertical lines over the top of it using draw_plot(). For the single legend, leverage the following SO answer:
Align multiple plots in ggplot2 when some have legends and others don't
The code:
#!/usr/bin/env Rscript
if (!require("pacman")) install.packages("pacman")
pacman::p_load(ggplot2, cowplot)
### Create some garbage data to plot
d0 <- data.frame(foo=c(0,0,0,0,0),bar=c("SX_RUNNYNOSE","SX_COUGH","SX_HEADACHE","SX_MALAISE","SX_MYALGIA"))
d1 <- data.frame(foo=c(1,2,3,4,5),bar=c("SX_RUNNYNOSE","SX_COUGH","SX_HEADACHE","SX_MALAISE","SX_MYALGIA"))
### Create a plot with 0 data but having the axis titles and vertical lines
p0 <- ggplot(d0, aes(x=seq(1,5), y=foo, fill=bar)) +
geom_bar(stat="identity") +
theme(axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.line.x=element_blank(),
axis.line.y=element_blank(),
axis.ticks.x=element_blank(),
axis.ticks.y=element_blank()
) +
theme(legend.position = "none") +
geom_segment(aes(x=2, y=0, xend=2, yend=4.9), color='red') +
geom_text(aes(x=2, y=max(d1$foo), label="T0")) +
geom_segment(aes(x=3, y=0, xend=3, yend=4.9), color='red') +
geom_text(aes(x=3, y=max(d1$foo), label="T24")) +
labs(y="Continued Symptom Count Among Samples", x="Time Elapsed Since Viral Challenge")
### A bar pot with the sample data and only the bars (no axis, etc)
### Make color of axis titles white to match the background color so they are not visible
p1 <- ggplot(d1, aes(x=seq(1,5), y=foo, fill=bar)) +
geom_bar(stat="identity") +
theme(axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.line.x=element_blank(),
axis.line.y=element_blank(),
axis.ticks.x=element_blank(),
axis.ticks.y=element_blank(),
axis.title.x = element_text(colour = "white"),
axis.title.y = element_text(colour = "white")
) +
theme(legend.title=element_blank())
### Arrange bar plots and legends in a grid and use draw_plot to
### overlay the single axis titles and vertical bars across all
### plots
g <- plot_grid(
plot_grid(
p1 + theme(legend.position = "none")
, p1 + theme(legend.position = "none")
, p1 + theme(legend.position = "none")
, ncol = 1
, align = "h"
, labels=c("Rhinovirus", "H3N2", "H1N1")
, hjust=c(-0.5,-1,-1)) +
draw_plot(p0, 0, 0, 1, 1, 1)
, plot_grid(
ggplot()
, get_legend(p1)
, ggplot()
, ncol =1)
, rel_widths = c(9,3)
)
g
The result:
Related
I'm working with a chemistry dataset, where I have 11 different chemicals, here labeled under the column c1,c2,...c11
I have made pie charts using library(ggplot2) , and would like to do 2 things with my plot.
Display all variables in the legend in a horizontal fashion (done), and not have them stacked (not done), as you see in my example. Having just one line would be great. 2 lines could also be acceptable.
Change colors to be color-blind friendly
Here is a pretend dataset we can work with so you can see what I have at this point. I have tried searching "legend margins" to increase the area the legend is plotted on, but to no avail.
data <- read.delim("https://pastebin.com/raw/MS5GLAxa", header = T)
ggplot(data, aes(x="", y=ratio, fill=chemical)) +
geom_bar(stat="identity", width=1,position = position_fill()) + facet_wrap(~treatment, nrow=1)+
coord_polar("y", start=0)+
theme_void(base_size = 20)+
theme(legend.position=c(0.5, 1.2),legend.direction = "horizontal")+
theme(plot.margin=unit(c(0,0,0,0), 'cm'))
Some side bonuses here would be to be able to:
increase the size of the pie chart (I believe I achieved this with making my margins as small as possible on the sides)
have the pie chart have solid colors, and no white lines in graph
Use guides to make the number of rows to 1 and use scale_fill_brewer with color blindness friendly palette.
ggplot(data, aes(x="", y=ratio, fill=chemical)) +
geom_bar(stat="identity", width=1,position = position_fill()) +
facet_wrap(~treatment, nrow=1)+
coord_polar("y", start=0) +
scale_fill_brewer(palette="Paired") +
theme_void(base_size = 20) +
theme(legend.position=c(0.5, 1.5),legend.direction = "horizontal",
plot.margin=unit(c(0,0,0,0), 'cm')) +
guides(fill = guide_legend(nrow = 1)) # if required nrow = 2
I'm working with a plot analogous to the following:
ggplot(data=mtcars, aes(x=wt, y=mpg, color=carb)) +
geom_line() + facet_grid(gear ~ .) +
ggtitle(expression("Title")) +
labs(caption = "Sources: Compustat, Author's Calculations") +
theme(plot.title = element_text(size = 20, hjust = 0.5),
plot.caption=element_text(size=8, hjust=.5),
strip.background = element_blank(),
strip.text = element_blank(),
legend.title = element_blank())
I'm trying to do the following:
Insert a legend beneath each of the 3 facets, each legend specific to the facet above it.
Insert one plot title (as opposed to the same title above each facet).
Insert one caption beneath the final facet (as opposed to three captions beneath each facet).
I was able to reproduce this example on assigning a legend to each facet.
However, the plot title was placed above and the caption below each facet. Also, this example uses facet_wrap and not facet_grid.
Thank you in advance.
library(dplyr)
library(ggplot2)
tempgg <- mtcars %>%
group_by(gear) %>%
do(gg = {ggplot(data=., aes(x=wt, y=mpg, color=carb)) +
geom_point() +
labs(x = NULL) +
guides(color = guide_colorbar(title.position = "left")) +
theme(plot.title = element_text(size = 20, hjust = 0.5),
plot.caption=element_text(size=8, hjust=.5),
legend.position = "bottom")})
tempgg$gg[1][[1]] <- tempgg$gg[1][[1]] + labs(title = "Top title")
tempgg$gg[3][[1]] <- tempgg$gg[3][[1]] + labs(x = "Axis label", caption = "Bottom caption")
tempgg %>% gridExtra::grid.arrange(grobs = .$gg)
This isn't the most elegant way to do it. Each of the three grobs gets an equal space when you grid.arrange them, so the first and last ones are squished from the title and caption taking up space. You could add something like heights = c(3,2,3) inside the grid.arrange call, but you'd have to fiddle with each of the heights to get it to look right, and even then it would be a visual approximation, not exact.
To do it the more precise way, you'd need to look at the underlying gtables in each of the grobs. https://stackoverflow.com/users/471093/baptiste is the expert on that.
Update:
I used a #baptiste solution, which is still not particularly elegant, but gives you the same plot space for each panel. Use this snippet in place of the last line above.
tempggt <- tempgg %>% do(ggt = ggplot_gtable(ggplot_build(.$gg))) %>% .$ggt
gg1 <- tempggt[[1]]
gg2 <- tempggt[[2]]
gg3 <- tempggt[[3]]
gridExtra::grid.arrange(gridExtra::rbind.gtable(gg1, gg2, gg3))
I want to combine these two graphs :
p1 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
facet_wrap(~ Species)
p2 <- ggplot(iris, aes(Sepal.Length)) +
geom_density()
To combine, I do :
multiplot(p1, p2, cols = 2)
But it is not the desired shape.
I would like the graph p2 has the same dimensions than others and is situated just next to the last faceted graph.
Thanks for help
Not sure if this is applicable in you generic case, but with facet_grid instead of facet_wrap, you can use the margins argument:
library(ggplot2)
ggplot(iris, aes(Sepal.Length)) +
geom_density() +
facet_grid(. ~ Species, margins = T)
If you question is more generic the answer probably lies in grid.arrange.
Something like this could be a start:
library(gridExtra)
grid.arrange(arrangeGrob(p1, p2,
widths = c(3,1),
heights = c(1,20),
layout_matrix = matrix(c(1,1,NA,2),2)))
As you can see there are several problems (different axes, top strip), but working with grid could gets complicated quickly.
This code should work:
p1 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
ylim(limits = c(0, 1.25))+
facet_wrap(~ Species)
p2 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
ggtitle("") + # ad empty title as place holder
labs(y = "", x = "") + # hide axis labels
ylim(limits = c(0, 1.25)) + # y axis values should be fixed in both plots
coord_fixed(ratio=20/1) + # ratio of x- and y-axis to reduce width of plot
theme(axis.ticks.y = element_blank(), axis.text.y = element_blank(), axis.line.y = element_blank(),
plot.margin=unit(c(0,0,0.65,-10), "lines")) # margin between plots = "0.65"
I fiddled a bit and used just different styling options to produce this result. If you have more plots than this one I would recommend to use one theme for all.
You can use either the multiplot function that you are already using
multiplot(p1, p2, cols = 2)
or you install the packages gridExtra and grid and use that one:
grid.arrange(p1, p2, ncol=2)
Hope this helps!
How can I increase the space between the keys of the legend of ggplot2 plot?
library(ggplot2)
ggplot(aes(mpg, wt, colour = factor(cyl)),
, data = mtcars) +
geom_point() +
theme(legend.direction = "horizontal",
legend.position = "bottom") +
guides(color = guide_legend(nrow=2))
I am looking for a ggplot2 option that add a kind of vertical adjustment between (key 4 and key 6) in the plot above? Should I create a custom legend key?
PS: I want to increase the blank space between boxes not between labels.
the desired plot is :
NOTE: No the question is not duplicated of the other question. We want here to add a vertical spacing between items that are already in multiple rows. In the other question we have 1-row legend and we want to add spaces (horizontal) between items.
An alternative (and probably easier) solution is using legend.key and legend.key.size in the theme part of your code:
ggplot(data = mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point() +
guides(color = guide_legend(nrow = 2)) +
theme(legend.direction = 'horizontal',
legend.position = 'bottom',
legend.key = element_rect(size = 5),
legend.key.size = unit(1.5, 'lines'))
this gives:
In case you are calling theme_bw or theme_classic before manipulating the legend, you should set the color of the legend rectangle:
legend.key = element_rect(size = 5, color = 'white') #or: color = NA
Here a solution using gtable. Basically I am extracting legend grobs table and I add a row in the legend table.
library(gtable)
library(grid)
## transform the ggplot to a grobs table
p_table <- ggplot_gtable(ggplot_build(p))
## extract legend
leg <- which(sapply(p_table$grobs, function(x) x$name) == "guide-box")
## this is the tricky part !
## add a row in the second position (pos=2)
p_table$grobs[[leg]]$grobs[[1]] <-
gtable_add_rows(p_table$grobs[[leg]]$grobs[[1]],
unit(0.5, "line"), ## you can increase the height here
pos=2) ## since I have 2 rows , I insert it in the middle
plot(p_table)
PS: I dont' know here how to coerce the table to a plot again! maybe someone else can help here ( I am just plotting it and losing the object structure)
Here is my data (called "data" and is a CSV format file):
attitude,order,min,max,mean,SpRate
Commanding,7,0.023005096,1.6517,0.681777825,5.66572238
Friendly,10,0.20565908,1.7535,0.843770095,6.191950464
Hostile,12,0.105828885,2.4161,1.128603777,6.493506494
Insincere,1,0.110689225,1.5551,0.730545923,5.115089514
Irony,4,0.089307133,2.2395,0.955312553,5.249343832
Joking,2,0.165717303,2.1871,0.94512688,5.141388175
Neutral,5,-0.044620705,1.5322,0.696879247,5.420054201
Polite,11,0.170151929,1.8467,0.873735105,6.191950464
Praising,8,0.192402573,2.0631,0.972857404,5.797101449
Rude,13,0.249746688,2.2885,1.100819511,6.644518272
Serious,6,0.011312206,1.7195,0.693606814,5.649717514
Sincere,9,-0.09135461,1.6409,0.659525513,5.813953488
Suggesting,3,0.072541529,1.8345,0.82999014,5.249343832
Here is my code:
library(ggplot2)
ggplot (data, aes(x=order))+
geom_rect(aes(xmin=order-0.1, xmax=order+0.1, ymin = min, ymax=max), size=1, alpha=0,color="black")+
geom_bar(aes(y=SpRate, fill="SpRate"),stat="identity", alpha=0.2, width=0.9)+
geom_point(aes(y=min, shape="min"), size=5, fill="white")+
geom_point(aes(y=mean, shape="mean"), size=5)+
geom_point(aes(y=max, shape="max"), size=5)+
scale_x_continuous(breaks=c(1:13), labels=c("Insincere","Joking","Suggesting","Irony","Neutral","Serious","Commanding","Praising","Sincere","Friendly","Polite","Hostile", "Rude"))+
xlab("")+ylab("")+theme_bw()+
theme(axis.text.x=element_text(size=25,angle=45, vjust=0.5, color="black"))+
theme(legend.text = element_text(size = 20))+
theme(legend.title = element_text(size = 20))+
labs(shape = "f0:", fill = "SpRate:")+
scale_shape_manual(values=c("min"=15,"max"=16,"mean"=18))+
scale_fill_manual(values= "black")+
theme(axis.text.y = element_text(size=20))
So, as you can see from the plot, there are two plots indeed: A rectanglular with points and a bar-plot, but the y-axis of bar-plot obviously not adapt into the y-axis presented well, so, how to add another y-axis in the right of the whole plot which could adjust for the bar-plot better? (i.e. I want the y-axis of rectangular presented from 0 to 2.5 and bar-plot from 0 to 7)
You could add the second y-axis in ggplot2.
Use this example for one panel plot (http://rpubs.com/kohske/dual_axis_in_ggplot2)
Use my example for multiple panel plot (Dual y axis in ggplot2 for multiple panel figure)