I'm reading Hadley Wickham's ggplot2 book and would like to get comments on my solution to one of the exercises:
Section 6.5.1
Exercise 1
The following code creates two plots of the mpg dataset. Modify the code so that the legend and axes match, without using facetting!
fwd <- subset(mpg, drv == "f")
rwd <- subset(mpg, drv == "r")
ggplot(fwd, aes(displ, hwy, colour = class)) + geom_point()
ggplot(rwd, aes(displ, hwy, colour = class)) + geom_point()
Here's my solution:
ggplot(fwd, aes(displ, hwy, colour = class)) +
geom_point() +
lims(x = c(0, 7), y = c(0, 45)) +
geom_point(aes(colour = class), alpha = 0, data = mpg) +
guides(colour = guide_legend(override.aes = list(alpha = 1)))
ggplot(rwd, aes(displ, hwy, colour = class)) +
geom_point() +
lims(x = c(0, 7), y = c(0, 45)) +
geom_point(aes(colour = class), alpha = 0, data = mpg) +
guides(colour = guide_legend(override.aes = list(alpha = 1)))
I feel like my idea is smart, but it wouldn't be efficient for larger datasets. Is there a more direct way to solve this problem? Or is this what the exercise is aiming at?
Just use drop = FALSE to keep all the factor levels.
mpg$class <- as.factor(mpg$class) # convert to factor
fwd <- subset(mpg, drv == "f")
rwd <- subset(mpg, drv == "r")
ggplot(fwd, aes(displ, hwy, colour = class)) + geom_point() + scale_colour_discrete(drop=FALSE)
ggplot(rwd, aes(displ, hwy, colour = class)) + geom_point() + scale_colour_discrete(drop=FALSE)
Related
I want to create a plot that looks like this:
x=1:20
y=sample(20)
df <- tibble(x=x,y=y)
ggplot(df,aes(x,y))+
geom_smooth()+
geom_point()
But the codes unabled to show legends.
Could anyone help me, thanks!
I'm perhaps being a bit over-literal in your requirements, but you could do:
tibble(x = 1:20, y = sample(20)) %>%
ggplot(aes(x, y)) +
geom_smooth(aes(linetype = "line")) +
geom_point(aes(shape = "point"), color = "red", size = 3) +
theme_gray(base_size = 20) +
theme(legend.position = c(0.75, 0.9),
legend.background = element_blank()) +
labs(shape = NULL, linetype = NULL)
You could set them inside their aes() as variables:
x <- 1:20
y <- sample(20)
library(ggplot2)
library(dplyr)
df <- tibble(x=x,y=y)
ggplot(df,aes(x,y))+
geom_smooth(aes(color = "line"))+
geom_point(aes(color = "point"))+
scale_color_manual(values = c("blue","red"))
With ggnewscale you could try:
library(tibble)
library(ggplot2)
library(ggnewscale)
x=1:20
y=sample(20)
df1 <- tibble(x=x, y=y)
ggplot(df1, aes(x, y))+
geom_smooth(aes(colour = "line"))+
scale_colour_manual(values = "black") +
labs(colour = NULL)+
new_scale_colour()+
geom_point(aes(colour = "point"))+
scale_colour_manual(values = "red")+
labs(colour = NULL)
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Created on 2022-11-27 with reprex v2.0.2
Here is my problem:
I do :
plot_grid(first_graph_by_mistake)
plot_grid(second_graph_on_purpuse)
ggsave("graph1.png")
vs ONLY
plot_grid(second_graph_on_purpose)
ggsave("graph2.png")
both the graphs look the same but when I do:
system("diff graph1.png graph2.png") it shows a difference.
Perhaps the png device is not flushed and some settings are different and that is why diff is showing a difference. How can I make the 2 graphs exactly the same ? That is my MAIN query.
I did the above in a very long piece of code. When I try to make a reprex example the diff does not show any difference between the 2 graphs. I am UNABLE to reproduce what I refer to in my query.
Here is the reprex:
library(cowplot)
library(grid)
plot.mpg.1 <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + geom_point(size=2.5)
plot.mpg.2 <- ggplot(mpg, aes(x = cty, y = displ, colour = factor(cyl))) + geom_point(size = 2.5)
plot.mpg.3 <- ggplot(mpg, aes(x = hwy, y = displ, colour = factor(cyl))) + geom_point(size = 2.5)
plot.mpg.4 <- ggplot(mpg, aes(x = drv, y = displ, colour = factor(cyl))) + geom_point(size = 2.5)
mygraphs <- list(plot.mpg.1,plot.mpg.2,plot.mpg.3,plot.mpg.4)
dummygraph <- mygraphs[[1]]
legend = get_legend(dummygraph + theme(legend.position = "bottom",legend.justification="center") + guides(fill = guide_legend(nrow = 1 )))
toplotlist <- lapply(mygraphs,function(x){x + theme(plot.margin = unit(c(0, 0, 0,0), "in"),legend.position="none")})
pmatrix <- do.call("plot_grid",toplotlist)
p<-plot_grid(pmatrix,legend,nrow=2,rel_heights = c(8,.2),rel_widths = c(10,1))
# Note : Please run first, the first section. Then run the second section.
######################################################################################################
# Without this line
# plot_grid(pmatrix,legend,nrow=2,rel_heights = c(64,1))
title <- ggdraw() + draw_label("My title", fontface='bold',size = 20)
semifinal <- plot_grid(title, p, ncol=1, rel_heights=c(0.1, 1))
blank <- grid.rect(gp=gpar(col="white"))
plot_grid(semifinal,blank,ncol=1,rel_heights=c(15,1))
ggsave(paste0("without_line.png"),height = 10,width = 10,dpi = 600)
########################################################################### ############################
# With this line
plot_grid(pmatrix,legend,nrow=2,rel_heights = c(64,1))
title <- ggdraw() + draw_label("My title", fontface='bold',size = 20)
semifinal <- plot_grid(title, p, ncol=1, rel_heights=c(0.1, 1))
blank <- grid.rect(gp=gpar(col="white"))
plot_grid(semifinal,blank,ncol=1,rel_heights=c(15,1))
ggsave(paste0("with_line.png"),height = 10,width = 10,dpi = 600)
###################################################################################################
# Now do
system("diff without_line.png with_line.png")
I have a data frame d like this:
d <- data.frame("name" = c("pippo","pluto","paperino"),
"id" = c(1,2,3),"count" = c(10,20,30),
"pvalue"=c(0.01,0.02,0.05),
geneRatio=c(0.5,0.8,0.2),
type=c("KEGG","Reactome","Reactome"))
and I plot a dotplot using the library ggplot:
ggplot(data = d,aes(geneRatio,name,size=count,colour = pvalue)) +
geom_point()+
ggtitle("Significantly Pathways") +
xlab("Gene Ratio") +
ylab("Pathways")+
theme(axis.text.y = element_text(color=d$type))
This is the plot at the moment
I would like to add to legend the information of "type" contained in dataframe d.
I would like to have a new item in the legend with color red = Reactome and color black= KEGG
Not saying that this is a good idea, but you can add a nonsensical geom to force the adding of a guide:
d <- data.frame("name" = c("pippo","pluto","paperino"),
"id" = c(1,2,3),
"count" = c(10,20,30),
"value"=c(0.01,0.02,0.05),
geneRatio=c(0.5,0.8,0.2),
type=c("KEGG","Reactome","Reactome")
)
library(ggplot2)
ggplot(data = d, aes(geneRatio,name,colour = pvalue)) +
geom_point(aes(size=count))+
geom_polygon(aes(geneRatio,name,fill = type)) +
ggtitle("Significantly Pathways") +
xlab("Gene Ratio") +
ylab("Pathways") +
scale_fill_manual(values = c('Reactome'='red', 'KEGG'='black')) +
theme(axis.text.y = element_text(color=d$type))
geom_polygon may not work with your actual data, and you may not find a suitable 'nonsensical' geom. I agree with #zx8754, a facet would be clearer:
ggplot(data = d, aes(geneRatio,name,colour = pvalue)) +
geom_point(aes(size=count)) +
ggtitle("Significantly Pathways") +
xlab("Gene Ratio") +
ylab("Pathways") +
facet_grid(type ~ ., scales = 'free_y', switch = 'y')
You could accomplish this using annotate, but it is a bit manual.
ggplot(data = d, aes(geneRatio, name, size = count, colour = pvalue)) +
geom_point() +
ggtitle("Significantly Pathways") +
xlab("Gene Ratio") +
ylab("Pathways")+
theme(axis.text.y = element_text(color=d$type)) +
annotate("text", x = 0.25, y = 3.5, label = "Reactome", color = "red") +
annotate("text", x = 0.25, y = 3.4, label = "KEGG", color = "black")
ggplot(all, aes(x=area, y=nq)) +
geom_point(size=0.5) +
geom_abline(data = levelnew, aes(intercept=log10(exp(interceptmax)), slope=fslope)) + #shifted regression line
scale_y_log10(labels = function(y) format(y, scientific = FALSE)) +
scale_x_log10(labels = function(x) format(x, scientific = FALSE)) +
facet_wrap(~levels) +
theme_bw() +
theme(panel.grid.major = element_line(colour = "#808080"))
And I get this figure
Now I want to add one geom_line to one of the facets. Basically, I wanted to have a dotted line (Say x=10,000) in only the major panel. How can I do this?
I don't have your data, so I made some up:
df <- data.frame(x=rnorm(100),y=rnorm(100),z=rep(letters[1:4],each=25))
ggplot(df,aes(x,y)) +
geom_point() +
theme_bw() +
facet_wrap(~z)
To add a vertical line at x = 1 we can use geom_vline() with a dataframe that has the same faceting variable (in my case z='b', but yours will be levels='major'):
ggplot(df,aes(x,y)) +
geom_point() +
theme_bw() +
facet_wrap(~z) +
geom_vline(data = data.frame(xint=1,z="b"), aes(xintercept = xint), linetype = "dotted")
Another way to express this which is possibly easier to generalize (and formatting stuff left out):
ggplot(df, aes(x,y)) +
geom_point() +
facet_wrap(~ z) +
geom_vline(data = subset(df, z == "b"), aes(xintercept = 1))
The key things being: facet first, then decorate facets by subsetting the original data frame, and put the details in a new aes if possible. Other examples of a similar idea:
ggplot(df, aes(x,y)) +
geom_point() +
facet_wrap(~ z) +
geom_vline(data = subset(df, z == "b"), aes(xintercept = 1)) +
geom_smooth(data = subset(df, z == "c"), aes(x, y), method = lm, se = FALSE) +
geom_text(data = subset(df, z == "d"), aes(x = -2, y=0, label = "Foobar"))
This is the current version of my figure:
require(MuMIn)
require(ggplot2)
data(Cement)
d <- data.frame(Cement)
dd <- melt(d,id.var = "y")
ggplot(dd,aes(x = y,y = value, group = variable)) +
geom_point(size = 2) +
theme_classic() +
facet_grid(variable ~ ., scales = "free") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
xlab("") +
ylab("") +
guides(colour = FALSE)
How can I
1) Alter this graph so that the X1, X2, X3, and X4 labels are on the left hand side and they read c("factor x^2","factor x^3","factor x^4","factor x^5"),
2) Is there a method for surrounding each panel with a box, to make them more distinguishable?
Try this,
library(ggplot2)
library(gtable)
p <- ggplot(mtcars, aes(mpg, cyl))+
facet_grid(gear~., labeller=label_both) + geom_point() +
theme(strip.text.y=element_text(angle=90)) + labs(y="")
g <- ggplotGrob(p)
g$layout[g$layout$name == "strip-right",c("l", "r")] <- 2
grid.newpage()
grid.draw(g)
A solution for question 1 (partial) and 2:
names(d) <- c("x^1","x^2","x^3","x^4","y")
dd <- melt(d,id.var = "y", variable.name="factor")
ggplot(dd, aes(x = y, y = value, group = factor)) +
geom_point(size = 2) +
theme_bw() +
facet_grid(factor ~ ., scales = "free", labeller = label_both) +
theme(axis.text.x = element_text(angle = 90, hjust = 1), panel.grid = element_blank()) +
xlab("") +
ylab("") +
guides(colour = FALSE)
which gives:
Using labeller is a good option (problem #1) and facet_grid and facet_wrap have a switch argument for moving facet labels around a bit (problem #2):
library("ggplot2")
x <- runif(100)
exp <- rep(1:4, each = 25)
y <- x^exp
df <- data.frame(x, y, exp)
# facet_grid
ggplot(df, aes(x, y)) +
facet_grid(exp ~ ., labeller = label_bquote(factor~x^.(exp)), switch = "y") +
geom_point() + labs(y="") +
theme(strip.background = element_blank()) # Remove facet border if you want
# facet_wrap
ggplot(df, aes(x, y)) +
facet_wrap(~ exp, ncol = 1, labeller = label_bquote(factor~x^.(exp)), switch = "y") +
geom_point() + labs(y="") +
theme(strip.background = element_blank())