此问题与Create custom geom to compute summary statistics and display them *outside* the plotting region相关(注意:所有功能都已简化;不会对正确的对象类型、NAs等进行错误检查)
在base 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")或者,您可以使用axis()函数将样本大小信息添加到x轴记号标签:
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")

虽然这在base R中是一项非常简单的任务,但在ggplot2中却非常复杂,因为很难获得用于生成曲线图的数据,而且还有相当于axis()的函数(例如,scale_x_discrete等)。没有与mtext()等效的工具,可以让您轻松地将文本放置在边距内的指定坐标处。
我尝试使用内置的stat_summary()函数来计算样本大小(即fun.y = "length"),然后将该信息放在x轴记号标签上,但据我所知,您无法提取样本大小,然后使用函数scale_x_discrete()将其添加到x轴记号标签中,您必须告诉stat_summary()您希望它使用哪个geom。您可以设置geom="text",但随后必须提供标签,关键是标签应该是样本大小的值,这是stat_summary()正在计算但无法获得的值(您还必须指定放置文本的位置,同样,很难找出放置文本的位置,使其直接位于x轴记号标签的下方)。
小插曲"Extending ggplot2“(http://docs.ggplot2.org/dev/vignettes/extending-ggplot2.html)向您展示了如何创建自己的统计函数,该函数允许您直接获取数据,但问题是,您总是必须定义一个geom来配合您的统计函数(即,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)显示每个面合并的两个面的样本大小。我将不得不在包装器函数中构建faceting,这与试图使用ggplot所提供的一切的观点不符。

如果有人对这个问题有任何见解,我将不胜感激。非常感谢您的宝贵时间!
发布于 2016-10-22 09:53:02
我已经更新了EnvStats包,使其包含一个名为stat_n_text的stat,它将在每个唯一的x值下面添加样本大小(唯一y值的数量)。有关更多信息和示例列表,请参阅stat_n_text的help file。下面是一个简单的例子:
library(ggplot2)
library(EnvStats)
p <- ggplot(mtcars,
aes(x = factor(cyl), y = mpg, color = factor(cyl))) +
theme(legend.position = "none")
p + geom_point() +
stat_n_text() +
labs(x = "Number of Cylinders", y = "Miles per Gallon")

发布于 2018-03-12 05:03:31
我的解决方案可能有点简单,但效果很好。
给出一个使用am刻面的例子,我从使用paste和\n创建标签开始。
mtcars2 <- mtcars %>%
group_by(cyl, am) %>% mutate(n = n()) %>%
mutate(label = paste0(cyl,'\nN = ',n))然后在ggplot代码中使用这些标签而不是cyl。
ggplot(mtcars2,
aes(x = factor(label), y = mpg, color = factor(label))) +
geom_point() +
xlab('cyl') +
facet_wrap(~am, scales = 'free_x') +
theme(legend.position = "none")来产生类似下图的东西。

发布于 2016-11-10 12:18:07
如果关闭裁剪,则可以使用geom_text打印x轴标签下的计数,但可能需要调整位置。我在下面的代码中包含了一个“轻推”参数。此外,下面的方法适用于所有方面(如果有的话)都是列方面的情况。
我知道你最终想要的代码可以在一个新的geom中工作,但也许下面的例子可以在geom中使用。
library(ggplot2)
library(dplyr)
pgg = function(dat, x, y, facet=NULL, nudge=0.17) {
# Convert x-variable to a factor
dat[,x] = as.factor(dat[,x])
# Plot points
p = ggplot(dat, aes_string(x, y)) +
geom_point(position=position_jitter(w=0.3, h=0)) + theme_bw()
# Summarise data to get counts by x-variable and (if present) facet variables
dots = lapply(c(facet, x), as.symbol)
nn = dat %>% group_by_(.dots=dots) %>% tally
# If there are facets, add them to the plot
if (!is.null(facet)) {
p = p + facet_grid(paste("~", paste(facet, collapse="+")))
}
# Add counts as text labels
p = p + geom_text(data=nn, aes(label=paste0("N = ", nn$n)),
y=min(dat[,y]) - nudge*1.05*diff(range(dat[,y])),
colour="grey20", size=3.5) +
theme(axis.title.x=element_text(margin=unit(c(1.5,0,0,0),"lines")))
# Turn off clipping and return plot
p <- ggplot_gtable(ggplot_build(p))
p$layout$clip[p$layout$name=="panel"] <- "off"
grid.draw(p)
}
pgg(mtcars, "cyl", "mpg")
pgg(mtcars, "cyl", "mpg", facet=c("am","vs"))


另一个可能更灵活的选项是将计数添加到绘图面板的底部。例如:
pgg = function(dat, x, y, facet_r=NULL, facet_c=NULL) {
# Convert x-variable to a factor
dat[,x] = as.factor(dat[,x])
# Plot points
p = ggplot(dat, aes_string(x, y)) +
geom_point(position=position_jitter(w=0.3, h=0)) + theme_bw()
# Summarise data to get counts by x-variable and (if present) facet variables
dots = lapply(c(facet_r, facet_c, x), as.symbol)
nn = dat %>% group_by_(.dots=dots) %>% tally
# If there are facets, add them to the plot
if (!is.null(facet_r) | !is.null(facet_c)) {
facets = paste(ifelse(is.null(facet_r),".",facet_r), " ~ " ,
ifelse(is.null(facet_c),".",facet_c))
p = p + facet_grid(facets)
}
# Add counts as text labels
p + geom_text(data=nn, aes(label=paste0("N = ", nn$n)),
y=min(dat[,y]) - 0.15*min(dat[,y]), colour="grey20", size=3) +
scale_y_continuous(limits=range(dat[,y]) + c(-0.1*min(dat[,y]), 0.01*max(dat[,y])))
}
pgg(mtcars, "cyl", "mpg")
pgg(mtcars, "cyl", "mpg", facet_c="am")
pgg(mtcars, "cyl", "mpg", facet_c="am", facet_r="vs")

https://stackoverflow.com/questions/40102613
复制相似问题