ggplot2: добавление информации о размере выборки в метки тика оси X

Этот вопрос связан сСоздайте пользовательский geom для вычисления сводной статистики и отображения ее * вне * области построения (ПРИМЕЧАНИЕ: все функции были упрощены; нет ошибок для проверки правильности типов объектов, NA и т. Д.)

В базе R довольно легко создать функцию, которая создает полосовую диаграмму с размером выборки, указанным под каждым уровнем переменной группировки: вы можете добавить информацию о размере выборки, используяmtext() функция:

stripchart_w_n_ver1 <- function(data, x.var, y.var) {
    x <- factor(data[, x.var])
    y <- data[, y.var]
# Need to call plot.default() instead of plot because 
# plot() produces boxplots when x is a factor.
    plot.default(x, y, xaxt = "n",  xlab = x.var, ylab = y.var)
    levels.x <- levels(x)
    x.ticks <- 1:length(levels(x))
    axis(1, at = x.ticks, labels = levels.x)
    n <- sapply(split(y, x), length)
    mtext(paste0("N=", n), side = 1, line = 2, at = x.ticks)
}

stripchart_w_n_ver1(mtcars, "cyl", "mpg")

или вы можете добавить информацию о размере выборки к меткам галочки по оси X, используяaxis() функция:

stripchart_w_n_ver2 <- function(data, x.var, y.var) {
    x <- factor(data[, x.var])
    y <- data[, y.var]
# Need to set the second element of mgp to 1.5 
# to allow room for two lines for the x-axis tick labels.
    o.par <- par(mgp = c(3, 1.5, 0))
    on.exit(par(o.par))
# Need to call plot.default() instead of plot because 
# plot() produces boxplots when x is a factor.
    plot.default(x, y, xaxt = "n", xlab = x.var, ylab = y.var)
    n <- sapply(split(y, x), length)
    levels.x <- levels(x)
    axis(1, at = 1:length(levels.x), labels = paste0(levels.x, "\nN=", n))
}

stripchart_w_n_ver2(mtcars, "cyl", "mpg")

Хотя это очень простая задача в базе R, в ggplot2 она невероятно сложна, потому что очень трудно получить доступ к данным, используемым для создания графика, и хотя существуют функции, эквивалентныеaxis() (например.,scale_x_discreteи т. д.)mtext() это позволяет легко размещать текст в указанных координатах внутри полей.

Я пытался использовать встроенныйstat_summary() функция для расчета размеров выборки (т.е.fun.y = "length"), а затем поместите эту информацию на метки тика оси X, но, насколько я могу судить, нельзя извлечь размеры выборки, а затем каким-то образом добавить их к меткам метки оси X с помощью функции.scale_x_discrete(), ты должен сказатьstat_summary() какой geom вы хотите использовать. Вы могли бы установитьgeom="text", но тогда вы должны предоставить метки, и дело в том, что метки должны быть значениями размеров выборки, чтоstat_summary() это вычисления, но вы не можете получить (и вам также нужно будет указать, где вы хотите разместить текст, и опять же, трудно определить, где разместить его так, чтобы он лежал прямо под осью X галочки).

Виньетка "Расширение ggplot2" (http://docs.ggplot2.org/dev/vignettes/extending-ggplot2.html) показывает, как создать собственную функцию статистики, которая позволяет получать данные напрямую, но проблема в том, что вам всегда нужно определить геом, чтобы использовать функцию статистики (т. е.ggplot думает, что вы хотите разместить эту информацию внутри графика, а не на полях); насколько я могу судить, вы не можете взять информацию, которую вы вычисляете, в своей пользовательской статистической функции, не построить ничего в области графика, а вместо этого передать информацию в функцию масштабирования, такую ​​какscale_x_discrete(), Вот моя попытка сделать это таким образом; лучшее, что я мог сделать, это поместить информацию о размере выборки в минимальное значение y для каждой группы:

StatN <- ggproto("StatN", Stat,
    required_aes = c("x", "y"), 
    compute_group = function(data, scales) {
    y <- data$y
    y <- y[!is.na(y)]
    n <- length(y)
    data.frame(x = data$x[1], y = min(y), label = paste0("n=", n))
    }
)

stat_n <- function(mapping = NULL, data = NULL, geom = "text", 
    position = "identity", inherit.aes = TRUE, show.legend = NA, 
        na.rm = FALSE, ...) {
    ggplot2::layer(stat = StatN, mapping = mapping, data = data, geom = geom, 
        position = position, inherit.aes = inherit.aes, show.legend = show.legend, 
        params = list(na.rm = na.rm, ...))
}

ggplot(mtcars, aes(x = factor(cyl), y = mpg)) + geom_point() + stat_n()

Я думал, что решил проблему, просто создав функцию-обертку дляggplot:

ggstripchart <- function(data, x.name, y.name,  
    point.params = list(), 
    x.axis.params = list(labels = levels(x)), 
    y.axis.params = list(), ...) {
    if(!is.factor(data[, x.name]))
    data[, x.name] <- factor(data[, x.name])
    x <- data[, x.name]
    y <- data[, y.name]
    params <- list(...)
    point.params    <- modifyList(params, point.params)
    x.axis.params   <- modifyList(params, x.axis.params)
    y.axis.params   <- modifyList(params, y.axis.params)

    point <- do.call("geom_point", point.params)

    stripchart.list <- list(
        point, 
        theme(legend.position = "none")
    )

    n <- sapply(split(y, x), length)
    x.axis.params$labels <- paste0(x.axis.params$labels, "\nN=", n)
    x.axis <- do.call("scale_x_discrete", x.axis.params)
    y.axis <- do.call("scale_y_continuous", y.axis.params)
    stripchart.list <- c(stripchart.list, x.axis, y.axis)           

    ggplot(data = data, mapping = aes_string(x = x.name, y = y.name)) + stripchart.list
}


ggstripchart(mtcars, "cyl", "mpg")

Однако эта функция неправильно работает с огранкой. Например:

ggstripchart(mtcars, "cyl", "mpg") + facet_wrap(~am)

показывает размеры выборки для обоих аспектов, объединенных для каждого аспекта. Я должен был бы встроить огранку в функцию-обертку, которая побеждает смысл попытки использовать всеggplot должен предложить.

Если у кого-то есть понимание этой проблемы, я был бы благодарен. Большое спасибо за ваше время!

Ответы на вопрос(3)

Ваш ответ на вопрос