Я делаю гистограмму с метками длинной оси, которые мне нужно обернуть и выровнять по правому краю. Единственная сложность в том, что мне нужно добавить выражение, чтобы иметь надстрочные индексы.
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))
который дает желаемый результат:
с правильно обернутым текстом со всеми метками, полностью выровненными по правому краю.
Однако теперь я пытаюсь добавить верхний индекс, используя приведенный ниже код, и выравнивание текста оси изменяется:
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")))
(Обратите внимание, что я не могу использовать юникод, как это рекомендуется другим людям с тем же вопросом, потому что он не работает со шрифтом, который я должен использовать).
Как я могу правильно выровнять текст оси, даже если одна из меток оси включает выражение?





Это странно, но если вектор (например, вектор символов меток) включает объект, созданный 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"
... и выражения всегда выравниваются по левому краю. Это не специфичное для ggplot явление; мы можем наблюдать это и в базовых функциях построения графиков:
# 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"))
Если бы мы могли заставить каждую метку рассматриваться отдельно, без влияния других меток в векторе меток, метки, не являющиеся выражениями, могли бы быть выровнены как обычные строки символов. Один из способов сделать это — преобразовать объект ggplot в grob и заменить один textGrob для меток оси Y несколькими текстовыми grob, по одному для каждой метки.
Подготовительная работа:
# 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"))
Взлом гроба:
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)
Можно ли использовать переменные внутри выражения?
Большое спасибо за невероятно подробный и полезный пост! это отлично решило мою проблему!