Is there a way to vertical align the symbols in a legend relative to the first line of the corresponding text?
plot(table(iris$species))
legend('right',c('A','B','long\ntext'), fill = colors(3))
The labels A and B are vertically aligned to the corresponding symbols, but the symbol corresponding to the the third label (long text with a line-break between the words) is aligned to the middle of this label.
I would prefer if the symbol would be aligned to the first line of the label (i.e. long).
The easiest way is to put a blank line before the text. That way, the first line of text will be aligned with the box:
pie(table(iris$Species), col = palette.colors(3, "Pastel 1"), cex = 2)
legend('right',c('A','B',' \nlong\ntext'), fill = palette.colors(3, "Pastel 1"),
cex = 2, box.lty = 0, y.intersp = 0)
iris <- iris
ggplot(iris, aes(x=Species, fill=Species)) +
geom_bar() +
scale_fill_manual(values=colors(3), labels=c('A', 'B', 'long\ntext')) +
theme(legend.position="right", legend.justification=0.5)
Related
I created a barplot and later added geom_text. I would like to make labels start at the bottom of each bar, I tried to use position vjust and hjust, also specify y = 0, but they didn't work, because labels have different lengths. I would like to solve it by specyfing geom_text arguments if possible. That's part of how my plot looks:
I want to make every label start at the same height, or just at the bottom of each bar
Code similar to my original
xxx <- sample(letters,1000, replace = T)
xxx <- data.frame(x=xxx)
text <- c(rep(c("b","adsasdasasd"),13))
library(tidyverse)
xxx %>%
count(x) %>%
ggplot(aes(x,n))+
geom_bar(stat="identity")+
geom_text(aes(x, label = text),y=0, angle=90)
It should work using both y=0 to specify the position relative to the graph, and hjust to specify the position of the text relative to the y:
library(tidyverse)
xxx <- sample(letters,1000, replace = T)
xxx <- data.frame(x=xxx)
text <- c(rep(c("b","adsasdasasd"),13))
xxx %>%
count(x) %>%
ggplot(aes(x,n))+
geom_bar(stat="identity")+
geom_text(aes(x, label = text), y=0, hjust="bottom", angle=90)
I'd like to place some text in my scatterplot, which I made with ggplot like you can see in the top left corner of the plot:
The text is now showing "Text" and "Variable", but should show more "Text" after the "Variable" and should be left aligned:
The requirements are:
It must have the format "Text" "Variable" "Text"
I need two or three rows
The rows should be left-aligned
What I did is using this code, but it might be not adequate for my intentions:
p1 + annotate(geom="text", x=1, y = 15, col="black",
label=paste("atop(' Mean diff = '*",bias,",'SD of diff = '*",sd,")"), parse=T)
I am making a bar chart with long axis labels which i need to wrap and right align. The only complication is i need to add a expression to have superscripts.
library(ggplot2)
library(scales)
df <- data.frame("levs" = c("a long label i want to wrap",
"another also long label"),
"vals" = c(1,2))
p <- ggplot(df, aes(x = levs, y = vals)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_x_discrete(labels = wrap_format(20))
which produces the desired result:
with properly wrapped text with all labels fully right aligned.
However now I attempt to add superscript using the below code, and the axis text alignment changes:
p <- ggplot(df, aes(x = levs, y = vals)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_x_discrete(labels = c(expression("exponent"^1),
wrap_format(20)("another also long label")))
(NB I cannot use unicode as is recommended to others with the same question because it does not work with the font I am required to use).
How can I get the axis text to be aligned right even when one of the axis labels includes an expression?
It's a strange thing, but if a vector (e.g. a character vector of labels) includes an object created by expression(), the whole vector appears to be treated as an expression:
# create a simple vector with one expression & one character string
label.vector <- c(expression("exponent"^1),
wrap_format(20)("another also long label"))
> sapply(label.vector, class) # the items have different classes when considered separately
[1] "call" "character"
> class(label.vector) # but together, it's considered an expression
[1] "expression"
... and expressions are always left-aligned. This isn't a ggplot-specific phenomenon; we can observe it in the base plotting functions as well:
# even with default hjust = 0.5 / vjust = 0.5 (i.e. central alignment), an expression is
# anchored based on the midpoint of its last line, & left-aligned within its text block
ggplot() +
annotate("point", x = 1:2, y = 1) +
annotate("text", x = 1, y = 1,
label = expression("long string\nwith single line break"))+
annotate("text", x = 2, y = 1,
label = expression("long string\nwith multiple line\nbreaks here")) +
xlim(c(0.5, 2.5))
# same phenomenon observed in base plot
par(mfrow = c(1, 3))
plot(0, xlab=expression("short string"))
plot(0, xlab=expression("long string\nwith single line break"))
plot(0, xlab=expression("long string\nwith multiple line\nbreaks here"))
Workaround
If we can force each label to be considered on its own, without the effect of other labels in the label vector, the non-expression labels could be aligned like normal character strings. One way to do this is to convert the ggplot object into grob, & replace the single textGrob for y-axis labels with multiple text grobs, one for each label.
Prep work:
# generate plot (leave the labels as default)
p <- ggplot(df, aes(x = levs, y = vals)) +
geom_bar(stat = "identity") +
coord_flip()
p
# define a list (don't use `c(...)` here) of desired y-axis labels, starting with the
# bottom-most label in your plot & work up from there
desired.labels <- list(expression("exponent"^1),
wrap_format(20)("another also long label"))
Grob hacking:
library(grid)
library(magrittr)
# convert to grob object
gp <- ggplotGrob(p)
# locate label grob in the left side y-axis
old.label <- gp$grobs[[grep("axis-l", gp$layout$name)]]$children[["axis"]]$grobs[[1]]$children[[1]]
# define each label as its own text grob, replacing the values with those from
# our list of desired y-axis labels
new.label <- lapply(seq_along(old.label$label),
function(i) textGrob(label = desired.labels[[i]],
x = old.label$x[i], y = old.label$y[i],
just = old.label$just, hjust = old.label$hjust,
vjust = old.label$vjust, rot = old.label$rot,
check.overlap = old.label$check.overlap,
gp = old.label$gp))
# remove the old label
gp$grobs[[grep("axis-l", gp$layout$name)]]$children[["axis"]]$grobs[[1]] %<>%
removeGrob(.$children[[1]]$name)
# add new labels
for(i in seq_along(new.label)) {
gp$grobs[[grep("axis-l", gp$layout$name)]]$children[["axis"]]$grobs[[1]] %<>%
addGrob(new.label[[i]])
}
# check result
grid.draw(gp)
The legend in ggplot can be moved to the bottom of the graphic as a horizontal legend by adding the following arguments to the theme function:
legend.position="bottom" moves the legend below the graph
legend.direction="horizontal" orients the legend to be horizontal.
However, not really...
The legend.direction="horizontal" simply seems to decrease the number of rows in the legend and the number of legend objects in each row.
This can be done manually using guides(color=guide_legend(nrow=x)
dat <- data.frame(plot = rep(letters,2), val = rep(1:length(letters),2))
library(ggplot2)
ggplot(dat, aes(x = val, y = val, color = plot)) +
geom_point() +
theme(legend.position="bottom") +
guides(color=guide_legend(nrow=2))
Regardless....
If you notice in the graphic output of the above code, even though I can control the "dimensions" of my legend (i.e., the number of rows), I can't figure out how to change the ordering of the legend from vertical to horizontal.
So instead of a being above b etc. ("vertically" sorted) as above, I want b to be added next to a ("horizontally" sorted).
How do I make my legend add objects horizontally vs vertically?
Like so:
Try adding byrow = TRUE to guide_legend:
ggplot(dat, aes(x = val, y = val, color = plot)) +
geom_point() +
theme(legend.position="bottom") +
guides(color=guide_legend(nrow=2, byrow = TRUE))
In ggplot, I want to label some error bars with asterisks ('*') to indicate significance level. The graph is arranged with category labels on the y axis, so that they are easily legible. This means that the error bars are horizontal, and the *'s need to align vertically with them. However, the symbol '*' is not vertically centred in a line of text, so it gets plotted too high using geom_text.
Reproducible example
set.seed(123)
x = data.frame(grp = LETTERS[1:8], val = sample(10,8))
se = runif(8, 0.1,2)
x$upper = x$val + se
x$lower = x$val - se
x$labs = sample(c('*','**', '***', ''), 8, T)
gg = ggplot(x, aes(grp,val)) +
geom_point() +
geom_errorbar(aes(ymax = upper, ymin=lower), width=0.3) +
scale_y_continuous(limits = c(-2,12)) +
coord_flip()
gg + geom_text(aes(y=upper+0.2, label=labs), size=8, hjust='left')
I know that I can nudge the label position like this:
gg + geom_text(aes(y=upper+0.2, label=labs), size=8, nudge_x = -0.2, hjust='left')
However, getting the correct value of nudge_x needs to be done in an ad-hoc manner and the correct value varies with size of graphics output, font size, number of categories on the y scale etc. Is there a way to get the labels to automatically align vertically? I tried using geom_point with shape=42 instead of geom_text to draw the asterisks. Although this solves the vertical alignment issue, it introduces its own problem with getting the spacing between a horizontal row of asterisks correct (i.e. getting '**' and '***' to print with the correct separation between adjacent symbols).
Just eyeballing it on my machine, it looks like this vjust adjustment seems to work, and I think it may be fairly robust to changes in device output size, font size, etc.
gg + geom_text(aes(y=upper+0.2, label=labs), size=8, hjust='left',vjust = 0.77)