On the below plot, I'd like to create an empty space on the x-axis at position 3. In other word, I'd like that the dots for wt>=3 and the axis scale when wt>=3 are shifted to the right side by some arbitrary chosen value. Does it make sense?
ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
I could simply modify the my data and add 0.5 to each value of mpg where wt>=3 but it doesn't solve the issue with the x-axis.
I might rephrase my question saying that on the below graph I'd like that the vertical line does not overlap the data and therefore all the data (and also the x-axis) should be shifted to the left by the thickness of the vertical line.
ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + geom_vline(xintercept=3, size=30)
I was thinking about facet_wrap or viewport. Maybe something like adding a constant to each value of mpg where wt>=3 and then, manually set the values for the x-axis.
Not entirely sure what you are looking for, and I get confused by watching the weird axis on my own plot... Something like this?
mtcars$wt2 <- with(mtcars, ifelse(wt > 3, wt+1, wt))
ggplot(mtcars, aes(x = wt2, y = mpg)) +
geom_point() +
annotate("rect", xmin = 3, xmax = 4, ymin = 0, ymax = 35, alpha = 0.2) +
scale_x_continuous(breaks = round(mtcars$wt2), label = round(mtcars$wt))
Similar to # Frank, and tested...
x <- mtcars
x$group <- ""
x[x$wt<3,]$group <- "1.LIGHT"
x[x$wt>=3,]$group <- "2.HEAVY"
library(ggplot2)
library(grid) #for unit(...)
ggplot(x, aes(x=wt,y=mpg)) +
geom_point() +
facet_grid(~group,scales="free",space="free") +
theme(panel.margin = unit(2, "lines"))
Produces this:
what about something like this?
mtcars <- transform(mtcars, split = ifelse(wt >= 3, "b", "a" ))
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
facet_wrap(~split, scales = "free_x")
Related
Is there a way to specify that a custom_annotation only applies to one facet of a ggplot?
For example, if I run the following code
library(tidyverse)
library(grid)
text_grob=grobTree(textGrob("text",x=0.5, y=0.6, rot=90,
gp=gpar(col="red")))
ggplot(mtcars, aes(x=mpg, y =drat))+
geom_point() +
facet_wrap(~cyl) +
annotation_custom(overrep_grob)
I get this
How can I only keep the rightmost red "text" annotation and not add the "text" annotation to the first two facets? Note I can't use geom_text or annotate because I need to make use of textGrob's relative text positioning
egg has geom_custom,
library(ggplot2)
library(grid)
library(egg)
d = data.frame(cyl=6, drat = 4, mpg = 15)
d$grob <- list(textGrob("text",rot=90, hjust = 0, gp=gpar(col="red")))
ggplot(mtcars, aes(x=mpg, y=drat))+
geom_point() +
facet_wrap(~cyl) +
geom_custom(data = d, aes(data = grob), grob_fun = identity)
You could also do this using geom_text by calculating the relative position of the text needed. Note that here, the relative position is slightly different than the one you use above because here I define the relative position as some proportion of the dynamic range. You can choose a different value for rel to get the position you need. I find that this way makes the positioning less arbitrary.
library(tidyverse)
rel_pos <- function(.data, var, rel){
var <- enquo(var)
.data %>%
summarise(x = sum(max(!!var), min(!!var))* rel) %>% .[1, "x"]
}
my_text <- data_frame(mpg = rel_pos(mtcars, mpg, 0.5),
drat = rel_pos(mtcars, drat, 0.6) ,
cyl = 8, lab = "text")
ggplot(mtcars, aes(x=mpg, y =drat))+
geom_point() +
facet_wrap(~cyl)+
geom_text(data = my_text, aes(label = lab), color = "red", angle = 90)
Created on 2018-08-15 by the reprex
package (v0.2.0).
Here's a bar chart:
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip()
Should produce this:
I would like to add labels on the end showing the total value of mpg in each bar. For example, 4cyl looks to be around about 290 just from eyeballing. I want to add a label showing the exact number to the bars.
I'd like to experiment and see how they look, so for completeness:
Inside at the top of the bars
Outside the bars along the top
Bonus is I'm able to control whether the labels display vertically or horizontally.
I found this SO post but have struggled to replicate the chosen answer. Here's my attempt:
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip() +
geom_text(aes(label = mpg))
Which gives an error:
Error: geom_text requires the following missing aesthetics: x, y
How can I add labels to the ends of the bars?
This would do what you need through generating a new data.frame for label plotting. You can customize the location of texts by adjusting nudge_y and angle.
library(dplyr)
tmp <- mtcars %>% group_by(cyl) %>% summarise(tot_mpg = sum(mpg))
tmp$cyl <- factor(tmp$cyl)
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip() + geom_text(data = tmp, nudge_y = 10, angle = 270,
aes(x = cyl, y = tot_mpg, label = tot_mpg))
I'm looking for a way to produce a diagonal slash from the bottom left the to top right corner of a cell within a plot made using geom_tile.
The input is a melted data frame with two categorical factor columns, sample and gene. I'd like to use something like geom_segment, but I'm not able to specify fractional increments. Any ideas on the best way to accomplish this?
edit: Here is a reproducible example, I can't share one from my own data, as it's protected patient information.
df <- data_frame( gene = c('TP53','TP53','MTOR','BRACA1'),
sample = c('A','B','A','B'),
diagonal = c(FALSE,TRUE,TRUE,FALSE),
effect = c('missense', 'nonsense', 'missense', 'silent') )
ggplot(df, aes(sample, gene)) + geom_tile(aes(fill = effect))
what I'm looking for:
One way to do it:
library(ggplot2)
df <- data.frame(
x = rep(c(2, 5, 7, 9, 12), 2),
y = rep(c(1, 2), each = 5),
z = factor(1:10),
w = rep(diff(c(0, 4, 6, 8, 10, 14)), 2)
)
p <- ggplot(df, aes(x, y)) + geom_tile(aes(fill = z))
gb <- ggplot_build(p)
p + geom_segment(data=gb$data[[1]][1:2, ],
aes(x=xmin, xend=xmax, y=ymin, yend=ymax),
color="white")
In your example, could also rely on the indices of the factor levels like this:
library(ggplot2)
df <- data.frame( gene = c('TP53','TP53','MTOR','BRACA1'),
sample = c('A','B','A','B'),
diagonal = c(FALSE,TRUE,TRUE,FALSE),
effect = c('missense', 'nonsense', 'missense', 'silent') )
df$cross <- c(F,T,T,F)
ggplot(df, aes(sample, gene)) +
geom_tile(aes(fill = effect)) +
geom_segment(data=transform(subset(df, !!cross), sample=as.numeric(sample), gene=as.numeric(gene)),
aes(x=sample-.49, xend=sample+.49, y=gene-.49, yend=gene+.49),
color="white", size=2)
(Note that I used data.frame and not dplyr::data_frame, so that both columns become factors.)
If you want a legend:
ggplot(df, aes(sample, gene)) +
geom_tile(aes(fill = effect)) +
geom_segment(data=transform(subset(df, !!cross), sample=as.numeric(sample), gene=as.numeric(gene)),
aes(x=sample-.49, xend=sample+.49, y=gene-.49, yend=gene+.49, color=cross),
size=2) +
scale_color_manual(values=c("TRUE"="white", "FALSE"=NA))
You can use geom_abline. You can tweak intercept and slope to get what you want. More info and examples here.
ggplot(df, aes(sample, gene)) +
geom_tile(aes(fill = effect)) +
geom_abline(intercept = 1, slope = 1, color="white", size=2)
If you don't actually want specific lines, but just want to highlight, you can simply draw dots:
ggplot(df, aes(sample, gene)) + geom_tile(aes(fill = effect)) +
geom_point(aes(sample, gene))
You can make it look like a line: geom_point(aes(sample, gene), shape='/', size=10, color='white')
To have the lines be only on some tiles, simply pass only the rows with those coordinates to geom_point: geom_point(data=filter(df, diagonal), aes(sample, gene))
Alternatively, you can hack it with a manual shape scale: geom_point(aes(sample, gene, shape=diagonal)) + scale_shape_manual(values=c(' ', '/'))
I have the following code snippet in R:
dat <- data.frame(cond = factor(rep("A",10)),
rating = c(1,2,3,4,6,6,7,8,9,10))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_point(aes(y=3)) +
geom_point(aes(y=3)) +
geom_point(aes(y=5))
This particular snippet of code produces a boxplot where one point goes over another (in the above case one point 3 goes over another point 3).
How can I move the point 3 so that the point remains in the same position on the y axis, but it is slightly moved left or right on the x axis?
This can be achieved by using the position_jitter function:
geom_point(aes(y=3), position = position_jitter(w = 0.1, h = 0))
Update:
To only plot the three supplied points you can construct a new dataset and plot that:
points_dat <- data.frame(cond = factor(rep("A", 3)), rating = c(3, 3, 5))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_point(aes(x=cond, y=rating), data = points_dat, position = position_jitter(w = 0.05, h = 0))
ggplot2 now includes position_dodge(). From the help's description: "Dodging preserves the vertical position of an geom while adjusting the horizontal position."
Thus you can either use it as geom_point(position = position_dodge(0.5)) or, if you want to dodge points that are connected by lines and need the dodge to the be the same across both geoms, you can use something like:
dat <- data.frame(cond = rep(c("A", "B"), each=10), x=rep(1:10, 2), y=rnorm(20))
dodge <- position_dodge(.3) # how much jitter on the x-axis?
ggplot(dat, aes(x, y, group=cond, color=cond)) +
geom_line(position = dodge) +
geom_point(position = dodge)
ggplot2 now has a separate geom for this called geom_jitter so you don't need the position = dodge or position = position_dodge()) argument. Here applied to OP's example:
dat <- data.frame(cond = factor(rep("A",10)),
rating = c(1,2,3,4,6,6,7,8,9,10))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_jitter(aes(y=c(3, 3, 5)))
Please pardon my ignorance if this is a simple question, but I can't seem to figure out how to underline any part of a plot title. I'm using ggplot2.
The best I could find was
annotate("segment") done by hand, and I have created a toy plot to illustrate its method.
df <- data.frame(x = 1:10, y = 1:10)
rngx <- 0.5 * range(df$x)[2] # store mid-point of plot based on x-axis value
rngy <- 0.5 * range(df$y)[2] # stores mid-point of y-axis for use in ggplot
ggplot(df, aes(x = x, y = y)) +
geom_point() +
ggtitle("Oh how I wish for ..." ) +
ggplot2::annotate("text", x = rngx, y = max(df$y) + 1, label = "underlining!", color = "red") +
# create underline:
ggplot2::annotate("segment", x = rngx-0.8, xend = rngx + 0.8, y= 10.1, yend=10.1)
uses bquote(underline() with base R
pertains to lines over and under nodes on a graph
uses plotmath and offers a workaround, but it didn't help
Try this:
ggplot(df, aes(x = x, y = y)) + geom_point() +
ggtitle(expression(paste("Oh how I wish for ", underline(underlining))))
Alternatively, as BondedDust points out in the comments, you can avoid the paste() call entirely, but watch out for the for:
ggplot(df, aes(x = x, y = y)) + geom_point() +
ggtitle(expression(Oh~how~I~wish~'for'~underline(underlining)))
Or another, even shorter approach suggested by baptiste that doesn't use expression, paste(), or the many tildes:
ggplot(df, aes(x = x, y = y)) + geom_point() +
ggtitle(~"Oh how I wish for "*underline(underlining))