Плохая идея? ggplotting объект класса S3
У многих объектов R есть методы S3, связанные с ними. Например, каждый R-регрессионный учебник содержит примерно следующее:
dat <- data.frame(x=runif(10))
dat$y <- dat$x+runif(10)
my.lm <- lm( y~x, dat )
plot(my.lm)
Отображает регрессионную диагностику.
Аналогично, у меня есть объект S3 для пакета, который состоит из списка, который в основном содержит несколько временных рядов. У меня есть метод plot.myobject
для него, который входит в список, вытягивает временные ряды и выстраивает их на одном графике. Я хотел бы переписать это как функцию ggplot2, чтобы она была более красивой и, возможно, более расширяемой.
Поскольку этот пакет предназначен для быстрого и быстрого запуска людей, , я хотел бы, чтобы это был однострочный с одним аргументом, как в plot(myobject)
, ggplot(myobject)
, или что бы ни была подходящей версией. Затем, как только они зацепились, они могут узнать больше о ggplot2
и настроить график на их содержание в сердце.
Мой первоначальный соблазн состоял в том, чтобы просто заменить внутренности метода plot.myobject
на использование ggplot2. Это, однако, похоже, что это может потерять меня в главных точках стиля.
Это плохая идея, и если да, то почему и какую альтернативу я должен использовать?
Ответы
Ответ 1
Согласно предложению Хэдли в комментариях, я представил общий S3 autoplot()
в репозиторий ggplot2
Github. Поэтому, если он будет принят и проверен, в будущем для этого использования должен быть autoplot
.
Обновление
autoplot
теперь доступен в ggplot2
.
Ответ 2
В ggplot2
существует существующая идиома, чтобы сделать именно то, что вы предлагаете. Он называется fortify
. Он принимает объект и создает версию объекта в форме, с которой может работать ggplot, т.е. Data.frame. В разделе 9.3 в книге Hadley ggplot2 описано, как это сделать, например, с использованием класса объектов S3 lm
. Чтобы увидеть это в действии, введите fortify.lm
в свою консоль, чтобы получить следующий код:
function (model, data = model$model, ...)
{
infl <- influence(model, do.coef = FALSE)
data$.hat <- infl$hat
data$.sigma <- infl$sigma
data$.cooksd <- cooks.distance(model, infl)
data$.fitted <- predict(model)
data$.resid <- resid(model)
data$.stdresid <- rstandard(model, infl)
data
}
<environment: namespace:ggplot2>
Вот мой собственный пример написания метода fortify
для tree
, первоначально опубликованного на список рассылки ggplot2
fortify.tree <- function(model, data, ...){
require(tree)
# Uses tree:::treeco to extract data frame of plot locations
xy <- tree:::treeco(model)
n <- model$frame$n
# Lines copied from tree:::treepl
x <- xy$x
y <- xy$y
node = as.numeric(row.names(model$frame))
parent <- match((node%/%2), node)
sibling <- match(ifelse(node%%2, node - 1L, node + 1L), node)
linev <- data.frame(x=x, y=y, xend=x, yend=y[parent], n=n)
lineh <- data.frame(x=x[parent], y=y[parent], xend=x,
yend=y[parent], n=n)
rbind(linev[-1,], lineh[-1,])
}
theme_null <- opts(
panel.grid.major = theme_blank(),
panel.grid.minor = theme_blank(),
axis.text.x = theme_blank(),
axis.text.y = theme_blank(),
axis.ticks = theme_blank(),
axis.title.x = theme_blank(),
axis.title.y = theme_blank(),
legend.position = "none"
)
И код сюжета. Обратите внимание, что данные, переданные в ggplot
, не являются объектами data.frame
, а tree
.
library(ggplot2)
library(tree)
data(cpus, package="MASS")
cpus.ltr <- tree(log10(perf) ~ syct+mmin+mmax+cach+chmin+chmax, cpus)
p <- ggplot(data=cpus.ltr) +
geom_segment(aes(x=x,y=y,xend=xend,yend=yend,size=n),
colour="blue", alpha=0.5) +
scale_size("n", to=c(0, 3)) +
theme_null
print(p)
![enter image description here]()
Ответ 3
Использование plot.myobject
легко запомнить и выполнить. Однако, если вы говорите о myobject
, у которого уже есть функции plot.myobject
, вы должны беспокоиться о разных версиях в разных пространствах имен. Но если это только для ваших собственных myobject
s, вы не потеряете ни одного стиля. Пакет nlme
, например, делает это широко, хотя с решетчатыми графами вместо ggplot.
Использование ggplot.myobject
является альтернативой; вам не придется беспокоиться о других версиях, если другие люди не начнут делать то же самое. Однако, как вы заметили, это нарушает парадигму использования ggplot
.
Другой альтернативой является использование нового имени, например gsk3plot
; вам никогда не придется беспокоиться о других версиях, это не слишком сложно запомнить, и вы можете сделать альтернативы сюжету для вашего сердца, не беспокоясь о конфликтах. Это, вероятно, то, что я бы выбрал, поскольку это дает понять аудитории, что эти сюжеты настраиваются, и это функция, которая делает сюжет таким, какой вы предпочитаете, и что, если они так склонны, они могут копаться и делать то же самое.
Ответ 4
ggplot
и ggplot2
обычно ожидают, что данные придут к ним в форме расплава(). Таким образом, вашим методам может потребоваться расплавление (из пакета plyr), а затем "сопоставить" полученные имена столбцов с аргументами в методах ggplot.