Я слежу за внутренним устройством библиотеки ggplot2
и пытаюсь понять, как непозиционная эстетика сопоставляется со значениями, которые передаются в grid
. В книге этот процесс описан как
Последняя часть преобразования данных — это обучение и отображение всей непозиционной эстетики, то есть преобразование любых дискретных или непрерывных входных данных, которые отображаются в графические параметры, такие как цвета, типы линий, размеры и т. д.».
Однако идея «обучения» данных появляется в тексте впервые.
Код этого процесса (из ggplot2:::ggplot_build.ggplot
) выглядит следующим образом:
# Train and map non-position scales and guides
npscales <- scales$non_position_scales()
if (npscales$n() > 0) {
lapply(data, npscales$train_df)
plot$guides <- plot$guides$build(npscales, plot$layers, plot$labels, data)
data <- lapply(data, npscales$map_df)
} else {
# Only keep custom guides if there are no non-position scales
plot$guides <- plot$guides$get_custom()
}
но я не могу следить за тем, что здесь на самом деле происходит. lapply(data, npscales$train_df)
действительно что-нибудь делает? Кажется, что он не сохранен, и я ожидал, что вместо этого будет data <- lapply(data, npscales$train_df)
, но функция, похоже, всегда возвращает NULL, независимо от того, с каким сюжетом я ее пытаюсь использовать.
Что означает «обучение» непозиционных данных в пакете ggplot2?
В книге, на которую вы ссылаетесь, во всех главах вверху страницы есть предостережение: «Вы читаете третье издание книги ggplot2, находящееся в разработке. В настоящее время эта глава является свалкой идей, и мы не не рекомендую читать.».
@Эдвард, эта часть аналогична и для версии 2: github.com/hadley/ggplot2-book:L190
В терминах ggplot2 «обучение» означает отслеживание возможных значений. Для непрерывных переменных это означает отслеживание диапазона, а для дискретных переменных — отслеживание уровней. «Отслеживание» здесь означает просмотр данных каждого слоя и обновление возможных значений на основе значений, встречающихся в данных.
Под капотом все это организовано классами DiscreteRange
и ContinuousRange
{scale}. Ниже приведены примеры их обновления.
# At first, tracked variable is empty
range <- scales::DiscreteRange$new()
range$range
#> NULL
# Observe data in first layer
range$train(c("A", "X"))
range$range
#> [1] "A" "X"
# Observe data in second layer
range$train(c("B"))
range$range
#> [1] "A" "B" "X"
Для непрерывных диапазонов.
# Again empty at first
range <- scales::ContinuousRange$new()
range$range
#> NULL
# Observe data in first layer
range$train(c(0, 10))
range$range
#> [1] 0 10
# Observe data in second layer
range$train(c(100))
range$range
#> [1] 0 100
Created on 2024-07-18 with reprex v2.1.1
В представленном вами коде эту работу выполняет lapply(data, npscales$train_df)
. Метод train_df
вызывается из-за побочного эффекта обновления диапазонов шкалы и возвращает NULL
, поскольку он не изменяет сам data
и результат функции не нужен.
«Непозиционная» часть означает, что эстетика x
и y
(и связанные с ней такие, как xmin
, yend
) не участвуют, поскольку требуют специального обращения и обучения гораздо раньше в процессе построения сюжета.
У меня нет ответа, но обычно, если вы видите цикл
lapply
, а результат не присваивается, есть две возможные причины: (i) функция в цикле вызывается из-за побочного эффекта или (ii) это делается для принудительной оценки чего-либо (это эффект определенного типа). Лично я предпочитаю использовать для таких целей циклfor
.