Inner ticks in ggplot - r

I want to add inner ticks to my plot given by a vector.
say my vector is myvec <- c(1,3,4:9, 12, 15)
and my plot:
library(ggplot2)
df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))
ggplot(df, aes(x=x, y=y)) + geom_point() +
scale_y_continuous(limits = c(0, 4))
I now want to add inside facing ticks at x= myvec, y=0 in blue color. How do I do it?
Tried to work with this solution, but could not use the vector.
Annotate ggplot with an extra tick and label

Try This:
df2<- cbind.data.frame("myvec" = myvec, z= rep(0, length(myvec)))
ggplot(df, aes(x=x, y=y)) + geom_point() +
scale_y_continuous(limits = c(0, 4)) +
geom_point(data=df2, aes(x=myvec, y=z), shape = "\U2714", color = "blue", size= 2)

Related

How to manually add a tick mark in ggplot2? [duplicate]

This question already has answers here:
ggplot2 annotate on y-axis (outside of plot)
(2 answers)
Closed 5 months ago.
I am quite new to the ggplot2 world in R, so I am trying to get familiar with the technicalities of plotting with ggplot2. In particular, I have a problem, which can be replicated by the following MWE:
ggplot(data.frame(x = c(1:10), y = c(1:10)), aes(x = c(1:10), y = c(1:10))) +
geom_line() +
geom_hline(aes(yintercept = 6), lty = 2)
This generates a simple graph of a diagonal line with a horizontal dashed line that cuts the y-axis at 6.
I would like to know whether there is a way to add a tick mark of 6 on the y-axis? In other words, say I simply showed this plot to a person without the code. I want the person to know that the horizontal dashed line cuts the y-axis at 6, which is not easily seen since 6 is not labelled currently.
Any intuitive suggestions will be greatly appreciated :)
You can use scale_y_continuous and give it all the points where you'd want a tick in the breaks argument.
library(ggplot2)
ggplot(data.frame(x = c(1:10), y = c(1:10)), aes(x = x, y = y)) +
geom_line() +
geom_hline(aes(yintercept = 6), lty = 2) +
scale_y_continuous(breaks = c(2, 4, 6, 8, 10))
in this specific example there is lots of "empty space" and you might consider adding the number within the plot using geom_text or geom_label if you think that is, what people should take away from your plot:
library(ggplot2)
ggplot(data.frame(x = c(1:10), y = c(1:10)), aes(x = x, y = y)) +
geom_line() +
geom_hline(aes(yintercept = 6), lty = 2) +
#scale_y_continuous(breaks = c(2, 4, 6, 8, 10)) +
geom_label(aes(x=2, y=6, label = "line at y = 6.0"))
Your data frame
df <- data.frame(x = c(1:10), y = c(1:10))
#Plotting
p <- ggplot(df, aes(x, y)) +
geom_point()
p
Custom function from here
It creates both x and y breaks
add_x_break <- function(plot, xval) {
p2 <- ggplot_build(plot)
breaks <- p2$layout$panel_params[[1]]$x$breaks
breaks <- breaks[!is.na(breaks)]
plot +
geom_vline(xintercept = xval) +
scale_x_continuous(breaks = sort(c(xval, breaks)))
}
add_y_break <- function(plot, yval) {
p2 <- ggplot_build(plot)
breaks <- p2$layout$panel_params[[1]]$y$breaks
breaks <- breaks[!is.na(breaks)]
plot +
geom_hline(yintercept = yval) +
scale_y_continuous(breaks = sort(c(yval, breaks)))
}
Define your break in your case y break
p <- add_y_break(p, 6)
p
Hope this helps
A bit of improvement with the ticks
p <- ggplot(df, aes(x, y)) +
geom_point()+
scale_x_continuous(breaks = round(seq(min(df$x), max(df$x), by = 0.5),1)) +
scale_y_continuous(breaks = round(seq(min(df$y), max(df$y), by = 0.5),1))
p
p <- add_y_break(p, 6)
p

Draw a box around the legend graphic in ggplot?

A similar sounding question is asked here. However, in the linked question, they put a bounding box around the legend and legend title. I was wondering if it's possible to put a bounding box around the legend graphic. For example,
library(ggplot2)
# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)
# Heatmap
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile()+
scale_fill_gradient(low = "white" ,high = "red")
The above code creates this plot:
Whereas, I am trying to create something like this:
I tried playing with legend.background function from ggplot but I can't get it to work for me.
Any suggestions as to how I would do this?
I don't think you can do this with theme() - you can do it with guides() though, e.g.
library(ggplot2)
# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)
# Heatmap
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile()+
scale_fill_gradient(low = "white" ,high = "red") +
guides(fill = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))
Edit per comment
Looking at the source code for new_scale() there should be a way to apply this solution to two of the same scales, but I can't figure it out. I reckon you should post another question and see if someone can solve it. Until then, maybe this workaround based on cowplot will work for you e.g.
## (I changed 'fill' to 'color' here, but the concept is the same)
library(ggplot2)
library(ggnewscale)
library(cowplot)
# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)
# Heatmap with both scales but legends aren't plotted
p1 <- ggplot(data, aes(X, Y, color = Z)) +
geom_tile() +
scale_color_gradient(low = "white", high = "red") +
new_scale_color() +
geom_point(aes(color = Z)) +
theme(legend.position = "none")
# Heatmap with only the first scale
p2 <- ggplot(data, aes(X, Y, color = Z)) +
geom_tile() +
scale_color_gradient(low = "white", high = "red") +
guides(color = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))
# Heatmap with only the second scale
p3 <- ggplot(data, aes(X, Y, color = Z)) +
geom_point(aes(color = Z)) +
guides(color = guide_colorbar(frame.colour = "black", frame.linewidth = 1.5))
# Grab the legends using cowplot::get_legend()
p2_legend <- get_legend(p2)
p3_legend <- get_legend(p3)
# Combine the legends one on top of the other
legends <- plot_grid(p2_legend, p3_legend, ncol = 1, nrow = 2)
# Combine the heatmap with the legends
plot_grid(p1, legends, ncol = 2, align = "h", rel_widths = c(0.9, 0.1))
## You may need to tinker with spacing/scale/rel_widths/rel_heights to get it looking right, but it should work out ok with some effort

overlaying plots from different dataframes in ggplot without messing with legend

I want to overlay two plots: one is a simple point plot where a variable is used to control the dot size; and another is a simple curve.
Here is a dummy example for the first plot;
library(ggplot2)
x <- seq(from = 1, to = 10, by = 1)
df = data.frame(x=x, y=x^2, v=2*x)
ggplot(df, aes(x, y, size = v)) + geom_point() + theme_classic() + scale_size("blabla")
Now lets overlay a curve to this plot with data from another dataframe:
df2 = data.frame(x=x, y=x^2-x+2)
ggplot(df, aes(x, y, size = v)) + geom_point() + theme_classic() + scale_size("blabla") + geom_line(data=df2, aes(x, y), color = "blue") + scale_color_discrete(name = "other", labels = c("nanana"))
It produces the error:
Error in FUN(X[[i]], ...) : object 'v' not found
The value in v is not used to draw the intended curse, but anyway, I added a dummy v to df2.
df2 = data.frame(x=x, y=x^2-x+2, v=replicate(length(x),0)) # add a dummy v
ggplot(df, aes(x, y, size = v)) + geom_point() + theme_classic() + scale_size("blabla") + geom_line(data=df2, aes(x, y), color = "blue") + scale_color_discrete(name = "other", labels = c("nanana"))
An the result has a messed legend:
What is the right way to achieve the desired plot?
You can put the size aes in the geom_point() call to make it so that you don't need the dummy v in df2.
Not sure exactly what you want regarding the legend. If you replace the above, then the blue portion goes away. If you want to have a legend for the line color, then you have to place color inside the geom_line aes call.
x <- seq(from = 1, to = 10, by = 1)
df = data.frame(x=x, y=x^2, v=2*x)
df2 = data.frame(x=x, y=x^2-x+2)
ggplot(df, aes(x, y)) +
geom_point(aes(size = v)) +
theme_classic() +
scale_size("blabla") +
geom_line(data=df2, aes(x, y, color = "blue")) +
scale_color_manual(values = "blue", labels = "nanana", name = "other")

I cannot apply a ColorBrewer palette on a line chart in ggplot2

p1 <- ggplot(data, aes(x, y, group=label))
p2 <- p1 + geom_line()+geom_point()
library(RColorBrewer)
p2 + scale_fill_brewer(palette="Oranges")
Sadly, I cannot post a image because of reputation limitation! The result is a line chart in with only black line and dots.
If I add "color=label" in the aes() part, the result uses the default color scheme, not my intended colors.
What should I do?
Something like this?
require(ggplot2)
df <- data.frame(a = seq(0, 90, 10), b = seq(10, 100, 10))
ggplot(df, aes(a, b, group = 1, color = b)) +
geom_line() + geom_point() +
scale_color_gradient(low = "green", high = "red")

Top to bottom alignment of two ggplot2 figures

I realize that the align.plots function from the ggExtra package has been deprecated and removed. However, I am using my own version as it seems to provide the specific functionality I need. I have looked into faceting to solve my problem but I don't think it will work for my particular issue. What seems to be the problem is that the top-to-bottom images don't align when I use coord_equal on one of them. This doesn't seem to affect left-to-right though. Here is a simplified (or at least as simple as I can make it) version of what I am trying to achieve.
Create some dummy data frames:
source('https://raw.github.com/jbryer/multilevelPSA/master/r/align.R')
require(psych)
df = data.frame(x=rnorm(100, mean=50, sd=10),
y=rnorm(100, mean=48, sd=10),
group=rep(letters[1:10], 10))
dfx = describe.by(df$x, df$group, mat=TRUE)[,c('group1', 'mean', 'n', 'min', 'max')]
names(dfx) = c('group', 'x', 'x.n', 'x.min', 'x.max')
dfy = describe.by(df$y, df$group, mat=TRUE)[,c('group1', 'mean', 'n', 'min', 'max')]
names(dfy) = c('group', 'y', 'y.n', 'y.min', 'y.max')
df2 = cbind(dfx, dfy[,2:ncol(dfy)])
range = c(0,100)
This will setup the three plots:
p1a = ggplot(df2, aes(x=x, y=y, colour=group)) + geom_point() +
opts(legend.position='none') +
scale_x_continuous(limits=range) + scale_y_continuous(limits=range)
p1 = p1a + coord_equal(ratio=1)
p2 = ggplot(df, aes(x=x, y=group, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + opts(legend.position='none')
p3 = ggplot(df, aes(x=group, y=y, colour=group)) + geom_point() +
scale_y_continuous(limits=range) + opts(legend.position='none')
The alignment top to bottom does not work with coord_equal
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1))
grid.newpage()
pushViewport( viewport( layout=grid_layout, width=1, height=1 ) )
align.plots(grid_layout, list(p1, 1, 2), list(p3, 1, 1), list(p2, 2, 2))
Broken Plot http://bryer.org/alignplots1.png
The fix is to add respect=TRUE to the grid.layout call:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1), respect=TRUE)
But if I don't use coord_equal the alignment works fine:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1))
grid.newpage()
pushViewport( viewport( layout=grid_layout, width=1, height=1 ) )
align.plots(grid_layout, list(p1a, 1, 2), list(p3, 1, 1), list(p2, 2, 2))
Working Plot http://bryer.org/alignplots2.png
ggplot2 now has ggplotGrob(), which may help with this.
First, we need to update the code used to generate the plots:
p1a = ggplot(df2, aes(x=x, y=y, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + scale_y_continuous(limits=range)
p1 = p1a + coord_equal(ratio=1) + theme_minimal() + theme(legend.position='none')
p2 = ggplot(df, aes(x=x, y=group, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + theme_minimal() + theme(legend.position='none')
p3 = ggplot(df, aes(x=group, y=y, colour=group)) + geom_point() +
scale_y_continuous(limits=range) + theme_minimal() + theme(legend.position='none')
p4 <- ggplot(df, aes(x = group, y = y)) +
geom_blank() +
theme(line = element_blank(),
rect = element_blank(),
text = element_blank(),
title = element_blank())
p4 will be blank; we just need the grob to draw.
Then we load the grid package and draw the grobs in a list arranged in rows and columns using cbind() and rbind().
library(grid)
grid.newpage()
grid.draw(
cbind(
rbind(ggplotGrob(p3), ggplotGrob(p4), size = "first"),
rbind(ggplotGrob(p1), ggplotGrob(p2), size = "first"),
size = "first"))
I'm not sure if this method will let you plot p3 in a different width and p2 in a different height, as you have them in the original example; I normally need a grid of similarly-sized graphs, and haven't needed to figure out different sizes.
This answer is partially based on partially based on https://stackoverflow.com/a/17463184/393354
Here is an example:
m <- matrix(c(3, 1, 0, 2), 2, byrow = T)
lay <- gglayout(m, widths = c(1, 3), heights = c(3, 1))
ggtable(p1, p2, p3, layout = lay)
you can use this by
install.packages('devtools')
library(devtools)
dev_mode()
install_github("ggplot2", "kohske", "cutting-edge")
library(ggplot2)
note that this branch is experimental, so maybe there are bugs.
To solve the problem using the align.plots method, specify respect=TRUE on the layout call:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1), respect=TRUE)

Resources