How can I add legends or labels to vertical lines? [duplicate] - r

I have a horizontal line in a ggplot and I would like to label it's value (7.1) on the y axis.
library(ggplot2)
df <- data.frame(y=c(1:10),x=c(1:10))
h <- 7.1
plot1 <- ggplot(df, aes(x=x,y=y)) + geom_point()
plot2 <- plot1+ geom_hline(aes(yintercept=h))
Thank you for your help.

It's not clear if you want 7.1 to be part of the y-axis, or if you just want a way to label the line. Assuming the former, you can use scale_y_continuous() to define your own breaks. Something like this may do what you want (will need some fiddling most likely):
plot1+ geom_hline(aes(yintercept=h)) +
scale_y_continuous(breaks = sort(c(seq(min(df$y), max(df$y), length.out=5), h)))
Assuming the latter, this is probably more what you want:
plot1 + geom_hline(aes(yintercept=h)) +
geom_text(aes(0,h,label = h, vjust = -1))

Similar to Chase's solution with a change of using the existing labels.
ggplot_build(plot1)$layout$panel_ranges[[1]]$y.major_source can be used to extract the exisitng labels and add new ones h.
plot1 + geom_hline(aes(yintercept=h)) +
scale_y_continuous(breaks = sort(c(ggplot_build(plot1)$layout$panel_ranges[[1]]$y.major_source, h)))

How about something like this?
plot1 + geom_hline(aes(yintercept=h), colour="#BB0000", linetype="dashed") +
geom_text(aes( 0, h, label = h, vjust = -1), size = 3)

This is a follow-up to Prradep's answer.
I think Prradep's answer works for an older version of ggplot2. I'm using ggplot2 version 3.1.0 and in order to extract the existing labels of plot1 in that version you have to use:
ggplot_build(plot1)$layout$panel_params[[1]]$y.major
This only works for LINEAR AXES! If you have a non-linear y-axis (for example logarithmic), then ggplot2 stores where tick marks would be if the axis were linear in $y.major. The actual tick mark labels are stored as a character vector in $y.labels. Therefore, for a non-linear y-axis you need to use:
as.numeric(ggplot_build(cl.plot.log)$layout$panel_params[[1]]$y.labels)

Related

Can you vary text size within the same ggplot2 axis?

I'd like to use ggplot2 to make a plot where the axis text size varies between labels- for example, larger font every five ticks with smaller font for the intervening ticks. I looked at using minor_breaks in scale_x_continuous, but I couldn't find a way to label the minor breaks.
The best I've got to work so far is a modification from this answer where I use bquote to pass an expression for the axis labels:
label_span <- 1:40
ShrinkIf <- Vectorize(function(val) {
if (val %% 5 == 0) return(as.character(val))
return(bquote(scriptstyle(.(as.character(val)))))
})
x_labels <- ShrinkIf(label_span)
x_labels <- purrr::invoke(expression, x_labels)
ggplot(mtcars, aes(x = mpg , y = hp)) +
geom_point() +
scale_x_continuous(breaks = label_span, labels = x_labels)
Is there a better way to go about this, or maybe a way with a little more control of the label size (or even font choice / text decoration, etc)? Thanks in advance for your help!
You can create a vector of text sizes and add it using element_text()
library(ggplot2)
ggplot(mtcars, aes(x = mpg, y = hp)) +
geom_point() +
theme(
axis.text.x = element_text(size = rep(c(12,24), 3))
)

changing ggplot legend unit scale

This question is motivated by a previous post illustrating various ways to change how axes scales are plotted in a ggplot figure, from the default exponential notation to the full integer value (when ones axes values are very large). While I am able to convert the axes scales from exponential notation to full values, I am unclear how one would achieve the same goal for the values appearing in the legend.
While I understand that one can manually change the length of the legend scale with "scale_color..." or "scale_fill..." followed by the "limits" argument, this does not appear to be a solution to getting my legend values to show "6000000000" rather than "6e+09" (or "0" rather than "0e+00" for that matter).
The following example should suffice. My hope is someone can point out how to implement the 'scales' package to apply for legend scales rather than axes scales.
Thanks very much.
library(ggplot2)
library(scales)
Data <- data.frame(
pi = c(2,71,828,1828,45904,523536,2874713,52662497,757247093,6999595749),
e = c(3,14,159,2653,58979,311599,7963468,54418516,1590576171, 99),
face = 1:10)
p <- ggplot(data = Data, aes(x=face, y=e, colour = pi))
myplot <- p + geom_point() +
scale_y_continuous(labels = comma) +
scale_color_gradientn(colours = rainbow(2), limits=c(0,7000000000))
myplot
Use the Comma formatter in scale_color_gradientn by setting labels = comma e.g.:
p <- ggplot(data = Data, aes(x=face, y=e, colour = pi))
myplot <- p + geom_point() +
scale_y_continuous(labels = comma) +
scale_color_gradientn(colours = rainbow(2), limits=c(0,7000000000), labels = comma)
myplot

Using math symbols in ggplot's annotate function

I am using ggplot to plot some data across 5 facets and I want to put some text that says "Delta = #" where Delta is the upper case math delta symbol and # is 1,2,3,4, or 5 based on which facet it is. Here is what I have:
annotate("text",x="baseline",y=75,label=paste(expression(Delta),"=",1:5))
My line of code works but it spells out Delta rather than giving me the Delta symbol. How can I get the math symbol?
Try this
df <- mtcars[2:6,]
ggplot(df, aes(mpg, disp))+
geom_point()+
annotate("text",df$mpg,df$disp,label=paste(("Delta * '=' *"), 1:5),
parse=TRUE, hjust = 1.1)
annotate() will give you the same annotation on each facet, you should use geom_text() instead, with a suitable data.frame to provide the mapping.
library(ggplot2)
ggplot(data.frame(f=1:2, lab = sprintf("Delta == %i", 1:2))) + facet_wrap(~f) +
geom_text(aes(label=lab), x=0, y=0, parse=TRUE)

facet_wrap Title wrapping & Decimal places on free_y axis (ggplot2)

I have a set of code that produces multiple plots using facet_wrap:
ggplot(summ,aes(x=depth,y=expr,colour=bank,group=bank)) +
geom_errorbar(aes(ymin=expr-se,ymax=expr+se),lwd=0.4,width=0.3,position=pd) +
geom_line(aes(group=bank,linetype=bank),position=pd) +
geom_point(aes(group=bank,pch=bank),position=pd,size=2.5) +
scale_colour_manual(values=c("coral","cyan3", "blue")) +
facet_wrap(~gene,scales="free_y") +
theme_bw()
With the reference datasets, this code produces figures like this:
I am trying to accomplish two goals here:
Keep the auto scaling of the y axis, but make sure only 1 decimal place is displayed across all the plots. I have tried creating a new column of the rounded expr values, but it causes the error bars to not line up properly.
I would like to wrap the titles. I have tried changing the font size as in Change plot title sizes in a facet_wrap multiplot, but some of the gene names are too long and will end up being too small to read if I cram them on a single line. Is there a way to wrap the text, using code within the facet_wrap statement?
Probably cannot serve as definite answer, but here are some pointers regarding your questions:
Formatting the y-axis scale labels.
First, let's try the direct solution using format function. Here we format all y-axis scale labels to have 1 decimal value, after rounding it with round.
formatter <- function(...){
function(x) format(round(x, 1), ...)
}
mtcars2 <- mtcars
sp <- ggplot(mtcars2, aes(x = mpg, y = qsec)) + geom_point() + facet_wrap(~cyl, scales = "free_y")
sp <- sp + scale_y_continuous(labels = formatter(nsmall = 1))
The issue is, sometimes this approach is not practical. Take the leftmost plot from your figure, for example. Using the same formatting, all y-axis scale labels would be rounded up to -0.3, which is not preferable.
The other solution is to modify the breaks for each plot into a set of rounded values. But again, taking the leftmost plot of your figure as an example, it'll end up with just one label point, -0.3
Yet another solution is to format the labels into scientific form. For simplicity, you can modify the formatter function as follow:
formatter <- function(...){
function(x) format(x, ..., scientific = T, digit = 2)
}
Now you can have a uniform format for all of plots' y-axis. My suggestion, though, is to set the label with 2 decimal places after rounding.
Wrap facet titles
This can be done using labeller argument in facet_wrap.
# Modify cyl into factors
mtcars2$cyl <- c("Four Cylinder", "Six Cylinder", "Eight Cylinder")[match(mtcars2$cyl, c(4,6,8))]
# Redraw the graph
sp <- ggplot(mtcars2, aes(x = mpg, y = qsec)) + geom_point() +
facet_wrap(~cyl, scales = "free_y", labeller = labeller(cyl = label_wrap_gen(width = 10)))
sp <- sp + scale_y_continuous(labels = formatter(nsmall = 2))
It must be noted that the wrap function detects space to separate labels into lines. So, in your case, you might need to modify your variables.
This only solved the first part of the question. You can create a function to format your axis and use scale_y_continous to adjust it.
df <- data.frame(x=rnorm(11), y1=seq(2, 3, 0.1) + 10, y2=rnorm(11))
library(ggplot2)
library(reshape2)
df <- melt(df, 'x')
# Before
ggplot(df, aes(x=x, y=value)) + geom_point() +
facet_wrap(~ variable, scale="free")
# label function
f <- function(x){
format(round(x, 1), nsmall=1)
}
# After
ggplot(df, aes(x=x, y=value)) + geom_point() +
facet_wrap(~ variable, scale="free") +
scale_y_continuous(labels=f)
scale_*_continuous(..., labels = function(x) sprintf("%0.0f", x)) worked in my case.

Customising legend size-symbol items in ggplot2

I'm mapping size to a variable with something like a log distribution - mostly small values but a few very large ones. How can I make the legend display custom values in the low-value range? For example:
df = data.frame(x=rnorm(2000), y=rnorm(2000), v=abs(rnorm(2000)^5))
p = ggplot(df, aes(x, y)) +
geom_point(aes(col=v, size=v), alpha=0.75) +
scale_size_area(max_size = 10)
print(p)
I've tried p + guides(shape=guide_legend(override.aes=list(size=8))) solution posted in this SO question, but it makes no difference in my plot. In any case I'd like to use specific legend size values e.g. v = c(10,25,50,100,250,500) instead of the default range e.g. c(100,200,300,400)..
Grateful for assistance.
To get different break points of size in legend, modify scale_size_area() by adding argument breaks=. With breaks= you can set breakpoints at positions you need.
ggplot(df, aes(x, y)) +
geom_point(aes(col=v, size=v), alpha=0.75) +
scale_size_area(max_size = 10,breaks=c(10,25,50,100,250,500))

Resources