ggplot geom_text geom_col geom_bar dodge bar r ggplot2

geom_text - ggplot r geom_bar



¿Cuál es el argumento de ancho en position_dodge? (1)

La documentación no explica exactamente qué es este argumento de width

  1. ¿De quién es el ancho que especifica?
  2. ¿Qué es la "unidad"?
  3. ¿Cuál es el valor predeterminado?

El valor predeterminado es width = NULL , pero prueba y error muestra que width = 0.9 parece producir el efecto predeterminado (ver postscript). Sin embargo, no pude encontrar dónde se establece dicho valor predeterminado en el código fuente de ggplot2 . Así,

  1. ¿Podría explicar cómo se implementa la ggplot2 predeterminada en el código ggplot2 ?

El espíritu de la pregunta es permitir a los usuarios de ggplot2 encontrar valores de width apropiados sin prueba y error. PD:

ggplot(data = df) + geom_bar(aes(x, y, fill = factor(group)), position = position_dodge(), stat = "identity") ggplot(data = df) + geom_bar(aes(x, y, fill = factor(group)), position = position_dodge(0.9), stat = "identity")


Primero daré respuestas muy breves a sus tres preguntas principales. Luego paso por varios ejemplos para ilustrar las respuestas más a fondo.

  1. ¿De quién es el ancho que especifica ?
    El ancho de los elementos a esquivar.

  2. ¿Qué es la "unidad "?
    El ancho real o virtual en unidades de datos de los elementos que se van a esquivar.

  3. ¿Cuál es el valor predeterminado ?
    Si no establece el width esquiva explícitamente, pero confía en el valor predeterminado, position_dodge(width = NULL) (o simplemente position = "dodge" ), el ancho de esquivar que se usa es el ancho real en unidades de datos del elemento para ser esquivado

Creo que su cuarta pregunta es demasiado amplia para SO. Consulte el código de collide y dodge y, si es necesario, haga una pregunta nueva y más específica .

En función del ancho de esquiva del elemento (junto con su posición horizontal original y el número de elementos que se apilan), se calculan las nuevas posiciones centrales ( x ) de cada elemento y los nuevos anchos ( xmin , xmax ). Los elementos se desplazan horizontalmente lo suficiente como para no superponerse con elementos adyacentes. Obviamente, los elementos anchos deben desplazarse más que los elementos estrechos para evitar la superposición.

Para tener una mejor idea de esquivar en general y el uso del argumento width en particular, muestro algunos ejemplos. Comenzamos con un diagrama de barra esquivado simple, con evasión predeterminada; podemos usar position = "dodge" o la position = position_dodge(width = NULL) más explícita position = position_dodge(width = NULL)

# some toy data df <- data.frame(x = 1, y = 1, grp = c("A", "B")) p <- ggplot(data = df, aes(x = x, y = y, fill = grp)) + theme_minimal() p + geom_bar(stat = "identity", position = "dodge") # which is the same as: # position = position_dodge(width = NULL))

Entonces (1) ¿de quién es el width en position_dodge y (2) cuál es la unidad?

En ?position_dodge podemos leer:

width : width esquiva, cuando es diferente al ancho de los elementos individuales

Por lo tanto, si usamos el width predeterminado , es decir, NULL , los cálculos de evasión se basan en el ancho de los elementos individuales .

Entonces, una respuesta trivial a su primera pregunta, " ¿ De quién es el ancho que especifica ?, Sería: el ancho de los elementos individuales .

Pero, por supuesto, nos preguntamos, ¿cuál es "el ancho de los elementos individuales"? Comencemos con las barras. De ?geom_bar :

width : width barra. De forma predeterminada, se establece en el 90% de la resolución de los datos.

Surge una nueva pregunta: ¿qué es la resolución? Vamos a ver ?ggplot2::resolution :

La resolución es la menor distancia distinta de cero entre valores adyacentes. Si solo hay un valor único [como en nuestro ejemplo], la resolución se define como uno.

Intentamos:

resolution(df$x) # [1] 1

Por lo tanto, el ancho de barra predeterminado en este ejemplo es 0.9 * 1 = 0.9

Podemos verificar esto mirando los datos que ggplot usa para representar las barras en el gráfico usando ggplot_build . Creamos un objeto de trazado con un diagrama de barras apilado, con barras de ancho predeterminado.

p2 <- p + geom_bar(stat = "identity", position = "stack")

La ranura relevante en el objeto es $data , que es una lista con un elemento para cada capa en el gráfico, en el mismo orden en que aparecen en el código. En este ejemplo, solo tenemos una capa, es decir, geom_bar , así que veamos la primera ranura:

ggplot_build(p2)$data[[1]] # fill x y label PANEL group ymin ymax xmin xmax colour size linetype alpha # 1 #F8766D 1 1 A 1 1 0 1 0.55 1.45 NA 0.5 1 NA # 2 #00BFC4 1 2 B 1 2 1 2 0.55 1.45 NA 0.5 1 NA

Cada fila contiene datos para ''dibujar'' una sola barra. Como puede ver, el ancho de las barras es de 0.9 ( xmax - xmin = 0.9 ). Por lo tanto, el ancho de las barras apiladas , que se utilizará en los cálculos de las nuevas posiciones y anchos esquivados, es 0.9 .

En el ejemplo anterior, utilizamos el ancho de barra predeterminado, junto con el ancho de esquiva predeterminado. Ahora hagamos que la barra sea un poco más ancha que el ancho predeterminado arriba (0.9). Use el argumento de width en geom_bar para establecer explícitamente el ancho de la barra (apilada) en, por ejemplo, 1. Tratamos de usar el mismo ancho de esquiva que el anterior ( position_dodge(width = 0.9) ). Por lo tanto, aunque hemos establecido el ancho real de la barra en 1, los cálculos de esquiva se realizan como si las barras tuvieran un ancho de 0.9. Veamos qué pasa:

p + geom_bar(stat = "identity", width = 1, position = position_dodge(width = 0.9), alpha = 0.8) p

Las barras se superponen porque ggplot desplaza las barras horizontalmente como si tuvieran un ancho (apilado) de 0.9 ( establecido en position_dodge ), mientras que las barras tienen un ancho de 1 ( establecido en geom_bar ).

Si usamos los valores de esquivar predeterminados , las barras se desplazan horizontalmente con precisión de acuerdo con el ancho de barra establecido :

p + geom_bar(stat = "identity", width = 1, position = "dodge", alpha = 0.8) # or: position = position_dodge(width = NULL)

A continuación, intentamos agregar algo de texto a nuestra trama usando geom_text . Comenzamos con el width evasión predeterminado (es decir, position_dodge(width = NULL) ), es decir, la evasión se basa en el tamaño de elemento predeterminado.

p <- ggplot(data = df, aes(x = x, y = y, fill = grp, label = grp)) + theme_minimal() p2 <- p + geom_bar(stat = "identity", position = position_dodge(width = NULL)) + geom_text(size = 10, position = position_dodge(width = NULL)) # or position = "dodge" p2 # Warning message: # Width not defined. Set with `position_dodge(width = ?)`

El esquivar el texto falla. ¿Qué pasa con el mensaje de advertencia? "¿El ancho no está definido?". Ligeramente críptico. Necesitamos consultar la sección Detalles de ?geom_text :

Tenga en cuenta que el "ancho" y la "altura" de un elemento de texto son 0, por lo que el apilamiento y la evasión de texto no funcionarán de forma predeterminada, [...] obviamente, las etiquetas tienen altura y anchura, pero son unidades físicas, no datos unidades .

Entonces, para geom_text , el ancho de los elementos individuales es cero. Esta es también la primera ''referencia oficial de ggplot'' a su segunda pregunta: la unidad de width está en unidades de datos .

Veamos los datos utilizados para representar los elementos de texto en la trama:

ggplot_build(p3)$data[[2]] # fill x y label PANEL group xmin xmax ymax colour size angle hjust vjust alpha family fontface lineheight # 1 #F8766D 1 1 A 1 1 1 1 1 black 10 0 0.5 0.5 NA 1 1.2 # 2 #00BFC4 1 1 B 1 2 1 1 1 black 10 0 0.5 0.5 NA 1 1.2

De hecho, xmin == xmax ; Por lo tanto, el ancho del elemento de texto en unidades de datos es cero.

¿Cómo lograr una evasión correcta del elemento de texto con ancho cero? De ejemplos en ?geom_text :

ggplot2 no sabe que quiere dar a las etiquetas el mismo ancho virtual que las barras [...] Entonces dígalo:

Por lo tanto, para que geom_text use el mismo ancho para los elementos geom_text que para los elementos geom_bar cuando se calculan nuevas posiciones, necesitamos establecer "el ancho virtual de esquiva en unidades de datos" del elemento de texto en el mismo ancho que las barras. Usamos el argumento de width de position_dodge para establecer el ancho virtual del elemento de texto en 0.9 (es decir, el ancho de la barra en el ejemplo anterior):

p2 <- p + geom_bar(stat = "identity", position = position_dodge(width = NULL)) + geom_text(position = position_dodge(width = 0.9), size = 10)

Verifique los datos utilizados para representar geom_text :

ggplot_build(p2)$data[[2]] # fill x y label PANEL group xmin xmax ymax colour size angle hjust vjust alpha family fontface lineheight # 1 #F8766D 0.775 1 A 1 1 0.55 1.00 1 black 10 0 0.5 0.5 NA 1 1.2 # 2 #00BFC4 1.225 1 B 1 2 1.00 1.45 1 black 10 0 0.5 0.5 NA 1 1.2

Ahora los elementos de texto tienen un ancho en unidades de datos: xmax - xmin = 0.9 , es decir, el mismo ancho que las barras. Por lo tanto, los cálculos de esquivar ahora se realizarán como si los elementos de texto tuvieran un cierto ancho, aquí 0.9. Renderiza la trama:

p2

¡El texto se esquivó correctamente!

Similar al texto, el ancho en unidades de datos de puntos ( geom_point ) y barras de error (por ejemplo, geom_errorbar ) es cero. Por lo tanto, si necesita esquivar tales elementos, debe especificar un ancho virtual relevante, en el que se basan los cálculos de esquivar. Consulte, por ejemplo, la sección Ejemplo de ?geom_errorbar :

Si desea esquivar barras y barras de error, debe especificar manualmente el ancho de esquivar [...] Debido a que las barras y barras de error tienen anchos diferentes, necesitamos especificar qué tan anchos son los objetos que estamos esquivando.

Aquí hay un ejemplo con varios valores de x en una escala continua:

df <- data.frame(x = rep(c(10, 20, 50), each = 2), y = 1, grp = c("A", "B"))

Digamos que deseamos crear una gráfica de barras esquivada con algo de texto sobre cada barra. Primero, solo verifique un diagrama de barras solo usando el ancho de esquiva predeterminado:

p <- ggplot(data = df, aes(x = x, y = y, fill = grp, label = grp)) + theme_minimal() p + geom_bar(stat = "identity", position = position_dodge(width = NULL)) # or position = "dodge"

Funciona como se esperaba. Luego, agregue el texto. Intentamos establecer el ancho virtual del elemento de texto al mismo ancho que las barras en el ejemplo anterior, es decir, "adivinamos" que las barras todavía tienen un ancho de 0.9 y que necesitamos esquivar los elementos de texto como si También tienen un ancho de 0.9:

p + geom_bar(stat = "identity", position = "dodge") + geom_text(position = position_dodge(width = 0.9), size = 10)

Claramente, el cálculo de esquivar las barras ahora se basa en un ancho diferente a 0.9 y establecer el ancho virtual a 0.9 para el elemento de texto fue una mala suposición. Entonces, ¿qué es el ancho de barra aquí? Nuevamente, el ancho de la barra es "[b] y predeterminado, establecido en el 90% de la resolución de los datos". Comprueba la resolución:

resolution(df$x) # [1] 10

Por lo tanto, el ancho de las barras (apiladas por defecto), en las que se calcula su nueva posición esquivada, ahora es 0.9 * 10 = 9 . Por lo tanto, para esquivar las barras y su texto correspondiente ''mano a mano'', necesitamos establecer el ancho virtual de también los elementos de texto en 9:

p + geom_bar(stat = "identity", position = "dodge") + geom_text(position = position_dodge(width = 9), size = 10)

En nuestro ejemplo final, tenemos un eje x categórico, solo una ''versión factorial'' de los valores x de arriba.

df <- data.frame(x = factor(rep(c(10, 20, 50), each = 2)), y = 1, grp = c("A", "B"))

En R, los factores son internamente un conjunto de códigos enteros con un atributo "niveles". Y de ?resolution :

Si x es un vector entero, se supone que representa una variable discreta, y la resolución es 1.

Por ahora, sabemos que cuando la resolution es 1, el ancho predeterminado de las barras es 0.9. Por lo tanto, en un eje x categórico, el ancho predeterminado para geom_bar es 0.9, y debemos establecer el width de geom_text para geom_text consecuencia:

ggplot(data = df, aes(x = x, y = y, fill = grp, label = grp)) + theme_minimal() + geom_bar(stat = "identity", position = "dodge") + # or: position = position_dodge(width = NULL) # or: position = position_dodge(width = 0.9) geom_text(position = position_dodge(width = 0.9), size = 10)