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
- ¿De quién es el ancho que especifica?
- ¿Qué es la "unidad"?
- ¿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í,
-
¿Podría explicar cómo se implementa la
ggplot2
predeterminada en el códigoggplot2
?
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.
-
¿De quién es el ancho que especifica
?
El ancho de los elementos a esquivar.
-
¿Qué es la "unidad
"?
El ancho real o virtual en unidades de datos de los elementos que se van a esquivar.
-
¿Cuál es el valor predeterminado
?
Si no establece elwidth
esquiva explícitamente, pero confía en el valor predeterminado,position_dodge(width = NULL)
(o simplementeposition = "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)