Работает ли stat_function() в ggplot2 с аргументами, отличными от векторов?

Я пытаюсь напечатать некоторые значения (geom_point) и поверх этого нарисовать некоторую функцию (stat_function) с ggplot2, однако я не могу построить функцию, потому что у нее есть аргумент списка типов.

Я хочу напечатать функцию create.new.func(x,W), которая получает два параметра (x, W), где x — числовое значение, а W — список, содержащий две матрицы разных размеров. Я пытался использовать строку

stat_function(fun= create.new.func,aes(colour="sep1"),args = list(W=superW))

Однако я продолжаю получать следующую ошибку:

Computation failed in `stat_function()`: non-conformable arguments##

Конечно, create.new.func(x,W=superW) отлично работает для любого x. Весь фрагмент кода, который я видел до сих пор, похоже, использует только векторы для параметра args, отсюда и мой вопрос.

Пример:

W <- list(matrix(c(1, -1, -1, 1), nrow = 2), matrix(c(1, 2)))

func <- function(x, W){
    sum(W[[2]] * (W[[1]] %*% c(1, x)))
}

ggplot() + 
    geom_point(aes(x = 0, y = 0)) + 
    theme_bw()+
    stat_function(fun = func, args = list(W), aes(colour = "black")) +
    scale_colour_manual("data", values = c("blue"))

person user57284    schedule 20.01.2019    source источник


Ответы (1)


Согласно ?stat_function, fun должны быть векторизованы. stat_function создает вектор значений x длины n (по умолчанию 101) между диапазоном значений x, передает его в функцию и отображает созданные значения x с результирующими значениями y. Например,

library(ggplot2)

ggplot() + stat_function(aes(x = 0:1), fun = sqrt)

Обратите внимание, что x должен иметь диапазон; если x = 0, результатом будет просто точка, хотя stat_function по-прежнему будет составлять вектор значений x (все они будут одинаковыми), то есть seq(0, 0, length.out = 101).

Таким образом, быстрый способ заставить ваш код работать — добавить полезный домен для x и перебрать x в func:

W <- list(matrix(c(1, -1, -1, 1), nrow = 2), matrix(c(1, 2)))

func <- function(x, W){
    sapply(x, function(x_i){
        sum(W[[2]] * (W[[1]] %*% c(1, x_i)))
    })
}

# it's vectorized now
func(1:10, W)
#> [1] 0 1 2 3 4 5 6 7 8 9

ggplot() + 
    geom_point(aes(x = 0, y = 0)) + 
    stat_function(aes(x = 0:1), fun = func, args = list(W = W))

В конечном счете, это не отличный способ векторизации func, потому что он просто зацикливается, а не пишет более качественный код/математику, поэтому он не очень эффективен. В этом случае 101 итерация простой функции все равно будет очень быстрой, поэтому ее дальнейшая оптимизация не обязательно стоит усилий. Для более медленных и сложных функций это может быть.

person alistaire    schedule 20.01.2019
comment
Спасибо за ваш удивительный ответ! Я использовал stat_function(aes(x = 0:1), fun = function(x,W) sapply(x, function(x) func(x,W)), args = list(W = W)) поэтому я не Мне нужно изменить мою исходную функцию. - person user57284; 20.01.2019
comment
Я не знаю, связано ли это, но если вы определите x перед stat_function, то его результирующий домен будет добавлением обоих доменов. Пример: df ‹- data.frame(x=seq(-2,2,.01),y=sqrt(abs(seq(-2,2,.01)))) ggplot() + geom_point(data=df ,aes(x = x, y = y)) + stat_function(aes(x = 0:1), fun = function(x,W) sapply(x, function(x) func(x,W)), args = list(W = W)) Домен для stat_function равен (-2,2), а не (0,1). Сейчас это не проблема, мне просто интересно, есть ли способ ограничить домен последней спецификацией. - person user57284; 20.01.2019
comment
Да, он использует пределы графика по умолчанию, поэтому, если разные слои имеют разные домены, он использует максимальный. Вы можете ограничить его явным интервалом с помощью параметра xlim. - person alistaire; 20.01.2019
comment
OK. Тогда, если у меня есть какой-то график и я хочу ограничить функцию более узким интервалом, то, может быть, лучше использовать что-то вроде аннотирования и ввода векторов вручную, нет? - person user57284; 21.01.2019
comment
Если прямые, то конечно. На самом деле это не является предполагаемой целью stat_function, так как ggplot воспроизводит функциональность curve. Если вы все еще хотите использовать stat_function, просто установите xlim. - person alistaire; 21.01.2019