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

Опитвам се да отпечатам някои стойности (geom_point) и отгоре на това да начертая някаква функция (stat_function) с ggplot2, но не мога да начертая функцията, защото има аргумент от тип list.

Искам да отпечатам функцията 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 = списък (W = W)) Домейнът за stat_function е (-2,2), а не (0,1). Сега това не е проблем в момента, просто се чудя дали има някакъв начин да огранича домейна до последната спецификация. - person user57284; 20.01.2019
comment
Да, той използва границите на диаграмата по подразбиране, така че ако различните слоеве имат различни домейни, той използва максимален. Можете да го ограничите до явен интервал с параметъра xlim. - person alistaire; 20.01.2019
comment
ДОБРЕ. След това, ако имам някакъв график и искам да огранича функция до по-тесен интервал, тогава може би е най-добре да използвам нещо като анотиране и да въвеждам векторите ръчно, нали? - person user57284; 21.01.2019
comment
Ако са прави линии, разбира се. Това всъщност не е предвидената цел на stat_function, което е начинът, по който ggplot възпроизвежда функционалността на curve. Ако все още искате да използвате stat_function, просто задайте xlim. - person alistaire; 21.01.2019