Ggplot выравнивание текста по оси вправо при использовании выражения

Я делаю гистограмму с метками длинной оси, которые мне нужно обернуть и выровнять по правому краю. Единственная сложность в том, что мне нужно добавить выражение, чтобы иметь надстрочные индексы.

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))

который дает желаемый результат:

Ggplot выравнивание текста по оси вправо при использовании выражения

с правильно обернутым текстом со всеми метками, полностью выровненными по правому краю.

Однако теперь я пытаюсь добавить верхний индекс, используя приведенный ниже код, и выравнивание текста оси изменяется:

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")))

Ggplot выравнивание текста по оси вправо при использовании выражения

(Обратите внимание, что я не могу использовать юникод, как это рекомендуется другим людям с тем же вопросом, потому что он не работает со шрифтом, который я должен использовать).

Как я могу правильно выровнять текст оси, даже если одна из меток оси включает выражение?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 317
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это странно, но если вектор (например, вектор символов меток) включает объект, созданный 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"))

illustration 1

illustration 2

Обходной путь

Если бы мы могли заставить каждую метку рассматриваться отдельно, без влияния других меток в векторе меток, метки, не являющиеся выражениями, могли бы быть выровнены как обычные строки символов. Один из способов сделать это — преобразовать объект 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)

result

Большое спасибо за невероятно подробный и полезный пост! это отлично решило мою проблему!

clairekelley 17.03.2019 22:29

Можно ли использовать переменные внутри выражения?

Alvaro Morales 22.04.2021 22:18

Другие вопросы по теме