ggplot: Insert linebreak when label is too long - r

I have to produce a scatter plot with many points.
I am already using the package "ggrepel" in order to avoid overlapping, but it sometimes still doesnt work. Is there a possibility to insert a linebreak into the labels (e.g. after a certain length)?
Thanks for help!
items <- c("A long description of the item",
"Another very long text descrbing the item",
"And finally another one ",
"This text exceeds the available space by far",
"Incredibly long text",
"Here we go with another one",
"A linebreak would help here",
"This has at least 20 characters")
items <- rep(items, 4)
df <- data.frame(
descs = items,
x = rnorm(n = length(items), mean = 2, sd = 2),
y = rnorm(n = length(items), mean = 2, sd = 2),
cat = as.factor(runif(length(items), min = 1, max = 6))
)
library(ggplot2)
library(tidyverse)
library(ggrepel)
df %>% ggplot(aes(x = x, y = y, color = cat)) + geom_point() +
#geom_text(aes(label = descs)) +
geom_text_repel(aes(label = descs)) +
theme_light() +
theme(legend.position="none")
rm(items)
rm(df)

You could use stringr::str_wrap to achieve line breaks at an appropriate point. For example, to limit lines to 20 characters, you can do:
df %>%
ggplot(aes(x = x, y = y, color = cat)) + geom_point() +
geom_text_repel(aes(label = stringr::str_wrap(descs, 20))) +
theme_light() +
theme(legend.position = "none")

Related

How to (re)arrange panels of facet_wrap/_grid?

R noob here. I have been stumped on this graph all day and solutions like this and this this seem to hold my answer but I cannot get them to work for me.
I have a data frame that is a large version of the below sample which I am trying to plot using ggplot.
# create data
df <- data.frame(
"ID" = rep(1:5, each = 4),
"Date" = c(seq(as.Date("2019/09/18"), by = "day", length.out = 4),
seq(as.Date("2019/09/18"), by = "day", length.out = 4),
seq(as.Date("2020/08/07"), by = "day", length.out = 4),
seq(as.Date("2020/09/12"), by = "day", length.out = 4),
seq(as.Date("2020/09/29"), by = "day", length.out = 4)),
"MaxDepth" = round(runif(20, min = 10, max = 50), 1),
"Trip" = rep(1:5, each = 4)
)
# plot using ggplot
ggplot(df, aes(Date, MaxDepth, col = factor(Trip))) +
geom_line() +
facet_grid(ID ~ format(Date, "%Y"), scales = "free_x") +
scale_y_reverse() +
scale_x_date(date_labels = "%b") +
labs(title = "Daily maximum depth\n",
x = "",
y = "Depth [m]\n",
col = "Fishing trip")
This turns out nicely as a two column, eleven row faceted graph with the fishing trips as colours.
However, it includes a lot of empty panels which I would like to avoid by creating a one column graph still with all eleven ID rows but that are separated by the same split label the two columns had. I.e. I would like the two individuals that were in the LHS 2019 plot to have that 2019 label on top, separated by the 2020 label from the other 9 individuals.
.
Hope this is clear. Please correct me or let me know what to improve for a better question.
Grateful for any help! Even if those are suggestions that this is not a good way of representation or something like this is simply not possible. Thank you all!
Here is a possible way. I am not sure whether it works for your real data.
library(ggplot2)
library(patchwork)
library(dplyr)
plot_fun <- function(dtt){
ggplot(dtt, aes(Date, MaxDepth, col = factor(Trip))) +
geom_line() +
facet_grid(ID ~ format(Date, "%Y"), scales = "free_x") +
scale_y_reverse() +
scale_x_date(date_labels = "%b") +
labs(x = NULL, y = NULL, col = "Fishing trip")
}
p1 <- plot_fun(df %>% filter(format(Date, '%Y') == '2019'))
p2 <- plot_fun(df %>% filter(format(Date, '%Y') == '2020'))
p1 / p2
ggsave('~/Downloads/test.png', width = 6, height = 6)

How to write a list of words in the second y-axis with ggplot? [duplicate]

This question already has an answer here:
How to add a free text entry as a legend to ggplot?
(1 answer)
Closed 2 years ago.
Let's assume I have the following dataframe:
df = data.frame(Date = seq(as.Date("2001-01-01"), as.Date("2020-12-31"), by = "day"),
Data = randn(length(seq(as.Date("2001-01-01"), as.Date("2020-12-31"), by = "day")),1),
stringsAsFactors = F)
and a vector of words:
key_words = c("ciao", "bye", "thanks", "for", "your", "help", "SO", "is", "amazing", "really")
I would like to plot it with ggplot by adding, in the second y-axis the vector of words key_words, similarly to the figure below:
This is the simple code to plot the graph in ggplot:
ggplot(df) + geom_line(aes(x = Date, y = Data), col = "blue") + labs(y = "", x = "") + theme_classic()
Is there anyone who can help me add key_words as a column in the figure above?
Thanks!
In case you want to link the key words place with the fist y axis, try this :
ggplot(df) + geom_line(aes(x = Date, y = Data), col = "blue") + labs(y = "", x = "") +
scale_y_continuous(limits=c(-4, 5), breaks = -5:5,
, sec.axis = sec_axis( ~. , breaks = -4:5, labels = key_words,
name = "name of the new axis")
)
+
theme_classic()

Two-line annotations using plotmath expressions in ggplot

I want to italicise a single character in the second line of a annotation in ggplot
Here's the plot
iris %>%
ggplot(aes(x = Sepal.Length,
y = Species,
fill = Species)) +
stat_summary(geom = "bar", fun = "mean") +
theme(legend.position = "none") -> p
Now I can annotate the plot like so and get a single character italicised while the rest is unitalicised.
p + annotate("text",
label = "italic(N)==74",
x = 3,
y = 2,
parse = T)
Now say I want a two-line annotation with certain characters pasted in. I can do it this way without using plotmath
p + annotate("text",
label = paste("AUC = ",
round(60.1876,3),
"\nN = ",
74,
sep = ""),
x = 3,
y = 2,
size = 4)
As you can see the N character is unitalicised. Is there any way to get it looking like the second graph but with the N italicised, either using plotmath or some other technique?
Use atop to draw text on top of text. See ?plotmath.
p +
annotate(
"text",
label = paste0("atop(AUC == ", round(60.1876, 3), ",italic(N) == 74)"),
x = 3,
y = 2,
size = 4,
parse = TRUE
)

Retaining trailing zeros from string plotted with `geom_text()` [duplicate]

This question already has an answer here:
Stop parsing out zeros after decimals in ggplot2's annotate
(1 answer)
Closed 2 years ago.
I have seen similar questions and solutions but none as far as I can see relatable to geom_text() in particular. Any guidance is greatly appreciated.
Say I want a plot point estimates and confidence intervals of:
# create tbl
ni <- tribble(
~ method, ~ mean_difference, ~ lo95, ~ hi95,
"NC", 3.235762, -0.5063099, 6.977835,
"IPTW", 3.256231, -0.5063099, 6.977835,
"EM", 5.642857, -1.995181, 13.280896,
)
Next I create a string var pasting together [rounded] mean_difference, lo95, and hi95 — which will be specified as the label for geom_text
# convert to point estimate and confidence intervals to strings (to keep trailing zeros for plot)
to_string <- function(
var,
n_digits = 1,
n_small = 1){
as.character(format(round(var, digits = n_digits), nsmall = n_small))
}
ni <- ni %>%
mutate(
mean_difference_lab = to_string(mean_difference),
lo95_lab = to_string(lo95),
hi95_lab = to_string(hi95),
lab = paste(
mean_difference_lab,
" (",
lo95_lab,
"-",
hi95_lab,
")",
sep = "")
)
This parses correctly in console.
print(ni$lab)
And yet, the trailing zeros are removed from the string when I plot it as:
ni %>%
ggplot(aes(x = mean_difference, y = method)) +
geom_point(
size = 6,
shape = 18) +
geom_errorbarh(aes(
xmin = lo95,
xmax = hi95,
height = 0
)) +
geom_text(aes(
family = 'Courier',
label = lab),
parse = TRUE,
nudge_y = -0.2) +
scale_x_continuous(breaks = seq(- 6, 14, 2))
Can any help spare my blushes, please?
if I understand your description you're getting:
but you want:
The only thing I changed was the argument parse=TRUE to parse=FALSE, i. e.
ni %>%
ggplot(aes(x = mean_difference, y = method)) +
geom_point(
size = 6,
shape = 18) +
geom_errorbarh(aes(
xmin = lo95,
xmax = hi95,
height = 0
)) +
geom_text(aes(
family = 'Courier',
label = lab),
parse = FALSE, # changed
nudge_y = -0.2) +
scale_x_continuous(breaks = seq(- 6, 14, 2))
(note that there are some awkward spaces when using parse=FALSE - these however are already in the data, i. e. what's shown in the plot is the same as what you get when looking at ni$lab)
Does this answer your question?

R: ggplot2 let the characters of geom_text exactly cover one X unit

I want to highlight text based on the position in a string, for example if we have this text:
this is a really nice informative piece of text
Then I want to say let's draw a rectangle around positions 2 till 4:
t[his] is a really nice informative piece of text
I tried to do so in ggplot2 using the following code:
library(ggplot2)
library(dplyr)
box.data <- data.frame(
start = c(4,6,5,7,10,7),
type = c('BOX1.start', 'BOX1.start', 'BOX1.start','BOX1.end', 'BOX1.end', 'BOX1.end'),
text.id = c(1,2,3,1,2,3)
)
text.data <- data.frame(
x = rep(1,3),
text.id = c(1,2,3),
text = c('Thisissomerandomrandomrandomrandomtext1',
'Thisissomerandomrandomrandomrandomtext2',
'Thisissomerandomrandomrandomrandomtext3')
)
ggplot(data = text.data, aes(x = x, y = text.id)) +
scale_x_continuous(limits = c(1, nchar(as.character(text.data$text[1])))) +
geom_text(label = text.data$text, hjust = 0, size = 3) +
geom_line(data = box.data, aes(x = start, y = text.id, group = text.id, size = 3, alpha = 0.5, colour = 'red'))
This produces the following graph:
My method fails as a letter does not cover exactly one unit of the x-axis, is there any way to achieve this?
I just figured out that I can split the string in characters and plot these, perhaps it is useful for someone else.
library(ggplot2)
library(dplyr)
library(splitstackshape)
# First remember the plotting window, which equals the text length
text.size = nchar(as.character(text.data$text[1]))
# Split the string into single characters, and adjust the X-position to the string position
text.data <- cSplit(text.data, 'text', sep = '', direction = 'long', stripWhite = FALSE) %>%
group_by(text.id) %>%
mutate(x1 = seq(1,n()))
# Plot each character and add highlights
ggplot(data = text.data, aes(x = x1, y = text.id)) +
scale_x_continuous(limits = c(1, text.size)) +
geom_text(aes(x = text.data$x1, y = text.data$text.id, group = text.id, label = text)) +
geom_line(data = box.data, aes(x = start, y = text.id, group = text.id, size = 3, alpha = 0.5, colour = 'red'))
Which produces this plot:
Perhaps the marking should extend a little but upwards and downwards, but that's an easy fix.

Resources