ggplot2: Hinzufügen von Stichprobengrößeninformationen zu x-Achsen-Teilstrichbeschriftungen

Diese Frage bezieht sich aufErstellen Sie ein benutzerdefiniertes Geom, um Zusammenfassungsstatistiken zu berechnen und diese * außerhalb * des Darstellungsbereichs anzuzeigen. (HINWEIS: Alle Funktionen wurden vereinfacht; es werden keine Fehlerprüfungen auf korrekte Objekttypen, NAs usw. Durchgeführt.)

In der Basis R ist es ziemlich einfach, eine Funktion zu erstellen, die ein Stripchart mit der unter jeder Ebene der Gruppierungsvariablen angegebenen Stichprobengröße erstellt: Sie können die Stichprobengrößeninformationen mit dem @ -Zeichen hinzufügemtext() Funktion:

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")

oder Sie können die Informationen zur Stichprobengröße mit @ zu den Beschriftungen der x-Achsen-Teilstriche hinzufügeaxis() Funktion:

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")

Während dies in Basis R eine sehr einfache Aufgabe ist, ist es in ggplot2 außerordentlich komplex, da es sehr schwierig ist, an die Daten zu gelangen, die zum Generieren des Diagramms verwendet werden, und obwohl es Funktionen gibt, die mit @ äquivalent sinaxis() (z.B.,scale_x_discrete usw.) Es gibt kein Äquivalent zumtext()it @ können Sie Text einfach an den angegebenen Koordinaten innerhalb der Ränder platzieren.

Ich habe versucht mit dem eingebautenstat_summary() -Funktion zum Berechnen der Stichprobengrößen (d. h.fun.y = "length") und platzieren Sie diese Informationen auf den Beschriftungen der x-Achsen-Teilstriche, aber soweit ich das beurteilen kann, können Sie die Stichprobengrößen nicht extrahieren und sie dann mit der Funktion @ irgendwie zu den Beschriftungen der x-Achsen-Teilstriche hinzufügescale_x_discrete(), du musst @ sagstat_summary() Welches Geom soll es verwenden? Du könntest @ setzgeom="text", aber dann müssen Sie die Beschriftungen angeben, und der Punkt ist, dass die Beschriftungen die Werte der Stichprobengrößen sein solltestat_summary() wird berechnet, ist aber nicht zu erreichen (und Sie müssten auch angeben, wo der Text platziert werden soll. Auch hier ist es schwierig, herauszufinden, wo er platziert werden soll, sodass er direkt unter dem x- Achsenmarkierungen).

Die Vignette "Erweitern von ggplot2" http: //docs.ggplot2.org/dev/vignettes/extending-ggplot2.htm) zeigt Ihnen, wie Sie Ihre eigene Statistikfunktion erstellen, mit der Sie direkt auf die Daten zugreifen können. Das Problem ist jedoch, dass Sie immer ein Geom definieren müssen, das zu Ihrer Statistikfunktion passt (d. h.ggplot denkt, Sie möchten diese Informationen innerhalb des Diagramms und nicht am Rand zeichnen); Soweit ich das beurteilen kann, können Sie die in Ihrer benutzerdefinierten Statistikfunktion berechneten Informationen nicht verwenden, nichts im Diagrammbereich zeichnen und die Informationen stattdessen an eine Skalierungsfunktion wie @ übergebescale_x_discrete(). Hier war mein Versuch, es so zu machen; Das Beste, was ich tun konnte, war, die Informationen zur Stichprobengröße auf den Mindestwert von y für jede Gruppe zu setzen:

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()

Ich dachte, ich hätte das Problem gelöst, indem ich einfach eine Wrapper-Funktion für @ erstellt habggplot:

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")

Diese Funktion funktioniert jedoch beim Facettieren nicht richtig. Beispielsweise

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

zeigt die Stichprobengrößen für beide Facetten kombiniert für jede Facette. Ich müsste Facettierung in die Wrapper-Funktion einbauen, die den Punkt beseitigt, zu versuchen, alles zu verwendenggplot hat anzubieten

Wenn jemand irgendwelche Einsichten zu diesem Problem hat, wäre ich dankbar. Vielen Dank für Ihre Zeit!

Antworten auf die Frage(6)

Ihre Antwort auf die Frage