3.12: Datos de trazado y ggplot2
- Page ID
- 55149
R proporciona algunas de las herramientas de visualización de datos más potentes y sofisticadas de cualquier programa o lenguaje de programación (aunque gnuplot
mencionado en el capítulo 12, “Miscelánea”, también es bastante sofisticado, y Python se está poniendo al día con bibliotecas cada vez más poderosas como matplotlib
). Una instalación básica de R proporciona un conjunto completo de herramientas para el trazado, y hay muchas bibliotecas disponibles para la instalación que amplían o complementan este conjunto básico. Uno de ellos es ggplot2
, que se diferencia de muchos otros paquetes de visualización de datos en que está diseñado alrededor de una “gramática” de gráficos bien concebida. [1]
El paquete ggplot2
no es el más potente ni flexible; los gráficos proporcionados por defecto con R pueden tomar ese título. Tampoco ggplot2
es lo más fácil: los programas más simples como Microsoft Excel son mucho más fáciles de usar. Lo que ggplot2
proporciona es un notable equilibrio de potencia y facilidad de uso. Como beneficio adicional, los resultados suelen ser de aspecto profesional con pocos ajustes, y la integración en R hace que la visualización de datos sea una extensión natural del análisis de datos.
Una breve introducción a los gráficos Base-R
Aunque este capítulo se centra en el paquete ggplot2
, vale la pena tener al menos familiaridad pasajera con algunas de las herramientas básicas de trazado incluidas con R. Primero, cómo se generan las gráficas depende de si estamos ejecutando R a través de una interfaz gráfica de usuario (como RStudio) o en la línea de comandos vía la consola R interactiva o el script ejecutable. Aunque escribir un programa no interactivo para producir parcelas puede parecer contradictorio, es beneficioso como registro escrito de cómo se produjo la trama para futuras referencias. Además, el trazado es a menudo el resultado final de un análisis complejo, por lo que tiene sentido pensar en la salida gráfica de manera muy similar a cualquier otra salida de programa que necesite ser reproducible.
Cuando se trabaja con una interfaz gráfica como RStudio, las gráficas se muestran por defecto en una ventana emergente o en un panel de trazado especial para su revisión. Alternativamente, o si estamos produciendo gráficas a través de un inicio de sesión remoto de línea de comandos, cada parcela se guardará en un archivo PDF llamado Rplots.pdf
. El nombre de este archivo se puede cambiar llamando a la función pdf ()
, dando un nombre de archivo para escribir. Para terminar de escribir el archivo PDF, se requiere una llamada a dev.off ()
(no toma parámetros).
La función de plotting más básica (distinta de hist ()
, que ya hemos visto) es plot ()
. Al igual que hist ()
, plot ()
es una función genérica que determina cómo debe ser la gráfica sobre la base de los atributos de clase de los datos que se le dan. Por ejemplo, dados dos vectores numéricos de igual longitud, produce una gráfica de puntos.
El contenido de dotplot.pdf
:
Para el resto de este capítulo, las llamadas pdf ()
y dev.off ()
no se especifican en ejemplos de código.
Podemos darle a la función plot ()
una pista sobre el tipo de plot que queremos usando el parámetro type =
, configurándolo en “p”
para puntos, “l”
para líneas, “b”
para ambos, y así sucesivamente. Para el trazado vectorial básico como el anterior, plot ()
respeta el orden en que aparecen los datos. Aquí está la salida de plot (vecx, vecy, type = “l”)
:
Habríamos tenido que ordenar uno o ambos vectores de entrada para obtener algo más razonable, si eso tiene sentido para los datos.
Otras funciones de trazado como hist ()
, curve ()
y boxplot ()
se pueden usar para producir otros tipos de trazado. Algunos tipos de trazado (aunque no todos) se pueden agregar a los resultados previamente trazados como una capa adicional estableciendo add = TRUE
. Por ejemplo, podemos producir una gráfica de puntos de dos vectores aleatorios, junto con un histograma con alturas de barras normalizadas usando hist ()
con probabilidad = VERDADERO y
.add = VERDADERO
Una trama como esta solo se verá razonable si los rangos de ejes son apropiados para ambas capas, lo cual debemos asegurarnos nosotros mismos. Esto lo hacemos especificando rangos con los parámetros xlim =
e ylim =
en la llamada a plot ()
, especificando los vectores longitud-dos.
Aquí hay una serie de reglas ocultas. Por ejemplo, se debe llamar a plot ()
antes de hist ()
, ya que add = TRUE
no es aceptado por la función plot ()
. Aunque hist ()
acepta los parámetros xlim
e ylim
, se ignoran cuando se usa hist ()
con add = TRUE
, por lo que deben especificarse en la llamada plot ()
en este ejemplo. Hay muchas funciones de trazado individuales como plot ()
e hist ()
, y cada una toma docenas de parámetros con nombres como “las”
, “cex”
, “pch”
y “tck”
(estos controlan la orientación de las etiquetas del eje y, fuente tamaño, formas de punto y tamaño de marca de marca, respectivamente). Desafortunadamente, la documentación de todas estas funciones y parámetros oscila entre escasa y confusamente compleja, aunque hay una serie de libros dedicados únicamente al tema de la trama en R.
A pesar de sus complejidades, uno de los principales beneficios de usar plot ()
es que, como genérico, la salida trazada a menudo se personaliza para el tipo de entrada. Como ejemplo, vamos a crear rápidamente algunos datos linealmente dependientes y ejecutarlos a través de la función de modelado lineal lm ()
.
Si le damos el lm_result
(una lista con atributo de clase “lm”
) a plot ()
, la llamada se enviará a plot.lm ()
, produciendo una serie de parcelas apropiadas para los parámetros y datos del modelo lineal. La primera de las cinco parcelas siguientes fue producida por la llamada a plot (vecx, vecy)
, mientras que las cuatro restantes son parcelas específicas de modelos lineales y fueron producidas por la llamada única a plot (lm_result)
como un archivo PDF de varias páginas.
Descripción general de ggplot2 y capas
Como se mencionó anteriormente, el paquete ggplot2
busca simplificar el proceso de trazado sin dejar de proporcionar una gran cantidad de flexibilidad y potencia mediante la implementación de una “gramática” de construcción gráfica. Dada esta estructura, vamos a tener que empezar por aprender algún vocabulario (más) especializado, seguido de alguna sintaxis (más) especializada. Existen varias formas de interactuar con ggplot2
de diversa complejidad. Comenzaremos primero con lo más complejo, para entender la estructura de la gramática, y luego pasaremos a métodos más simples que son más fáciles de usar (una vez enmarcados en términos de la gramática).
A diferencia de la función plot ()
genérica, que puede trazar muchos tipos diferentes de datos (como en el ejemplo del modelo lineal anterior), ggplot2
se especializa en trazar datos almacenados en marcos de datos.
Un “plot” en ggplot2
se compone de los siguientes componentes:
- Una o más capas, cada una representando cómo se deben trazar algunos datos. Las capas de trazado son las piezas más importantes, y constan de cinco subpartes:
- Los
datos
(un marco de datos), que contiene los datos a trazar. - Una
estadística
, que significa “mapeo estadístico”. Por defecto, esta es la estadística de“identidad”
(sin modificación) pero podría ser algún otro mapeo que procese el marco dedatos
y produzca un nuevo conjunto de datos que realmente se grafica. - Un
geom
, abreviatura de “objeto geométrico”, que especifica la forma a dibujar. Por ejemplo,“punto”
especifica que los datos deben trazarse con puntos (como en una gráfica de puntos),“línea”
especifica que los datos deben trazarse con líneas (como en una gráfica de líneas) y“bar”
especifica que los datos deben trazarse con barras (como en un histograma). - Un
mapeo
de “estética”, que describe cómo las propiedades delgeom
(por ejemplo, la posiciónx
ey
de los puntos, o sucolor
,tamaño
, etc.) se relacionan con las columnas de los datos transformados porestadísticas
. Cada tipo degeom
se preocupa por un conjunto específico de estética, aunque muchos son comunes. - Una
posición
para elgeom
; generalmente, esto es“identidad”
para sugerir que la posición delgeom
no debe ser alterada. Las alternativas incluyen“jitter”
, que agrega algo de ruido aleatorio a la ubicación (por lo que las formasgeom
superpuestas son más fáciles de ver).
- Los
- Una
escala
por cada estética utilizada en capas. Por ejemplo, el valorx
de cada punto se produce en una escala horizontal que podríamos desear limitar a un rango dado, y el valor decolor
de cada punto ocurre en una escala de colores que podríamos desear variar de púrpura a naranja, o negro a azul. - Una especificación
facetaria
, que describe cómo deben ocurrir los datos de paneles en múltiples parcelas similares. - Un sistema de
coordenadas
al que aplicar algunas escalas. Por lo general, no los modificaremos a partir de los valores predeterminados. Por ejemplo, el valor predeterminado parax
ey
es usar un sistema de coordenadascartesianas
, aunquepolar
es una opción. - Alguna información
del tema
, como tamaños de fuente y rotaciones, marcas de eje, relaciones de aspecto, colores de fondo y similares. - Un conjunto de valores predeterminados. Los valores por defecto son algo extraño de enumerar como parte específica de una parcela, ya que estas son las propiedades que no especificamos, pero
ggplot2
las hace un uso intensivo, por lo que vale la pena mencionarlas.
Cuando se instala con install.packages (“ggplot2")
(en la consola interactiva) y se carga con biblioteca (ggplot2)
, el paquete viene con un marco de datos llamado diamantes
. Cada fila de este marco de datos especifica cierta información sobre un solo diamante; con cerca de 54,000 filas y muchos tipos de columnas (incluyendo numéricas y categóricas), es un excelente conjunto de datos con el que explorar el trazado.
Empecemos explorando el concepto más importante en la lista de definiciones anterior: la capa y sus cinco componentes. Para crear una capa, podemos comenzar creando un objeto gg
“vacío” llamando a ggplot ()
sin parámetros. A esto agregaremos una capa con +
y llamando a la función layer ()
, especificando los cinco componentes que queremos. [2] Debido a que estos comandos de trazado se vuelven bastante largos, los dividimos sobre varias líneas (terminando líneas discontinuas con +
o,
para que el intérprete sepa que el comando no está terminado) y los sangramos para ayudar a indicar dónde están contribuyendo diferentes piezas.
Aquí, hemos especificado cada uno de los cinco componentes de capa descritos anteriormente. Para el mapeo
de la estética, existe una llamada interna a una función aes ()
que describe cómo la estética de los geoms (x
e y
, y el color
en este caso) se relacionan con columnas de los datos
ajustados por estadísticas
(en este caso, las columnas de salida de la estadística son idénticas a las columnas de entrada). [3] Finalmente, observamos que ggplot2
ha manejado sin problemas la columna categórica de corte
.
Para guardar el resultado en un archivo o cuando no se trabaja en una interfaz gráfica, podemos usar la función pdf ()
antes de la llamada a plot ()
seguida de dev.off ()
, como hicimos para los gráficos Base-R. Alternativamente, podemos usar la función especializada ggsave ()
, que también nos permite especificar el tamaño general de la gráfica (en pulgadas a 300 dpi por defecto para PDF).
Agreguemos una capa a nuestra trama que también trazará puntos en los ejes x
e y
, por quilate
y precio
. Esta capa adicional, sin embargo, utilizará una estadística “suave”
, y no colorearemos los puntos. (En versiones recientes de ggplot2
, este ejemplo de capa también requiere un params = list (method = “auto”)
que establece el método de suavizado de stat. A continuación veremos cómo escribir código más compacto con este y otros parámetros establecidos automáticamente).
En este caso, los datos originales han sido transformados por la estadística “suave”
, por lo que x = quilate, y = precio
ahora especifica las columnas en el marco de datos transformado por estado. Si tuviéramos que cambiar el geom
de esta capa a “line”
, obtendríamos una gráfica como abajo a la izquierda, y si añadimos un color = cut
en la llamada aes ()
, obtendríamos una gráfica como abajo a la derecha.
En la trama derecha de arriba, se han creado múltiples líneas; son un poco difíciles de ver, pero veremos cómo solucionarlo en un poco. Obsérvese que el orden de las capas importa: la segunda capa se trazó encima de la primera.
Esta segunda capa ilustra uno de los aspectos más confusos de ggplot2
, a saber, que los mapeos estéticos (propiedades de los geoms) y los mapeos de estadísticas interactúan. En la segunda capa anterior, especificamos aes (x = quilate, y = precio)
, pero también especificamos la estadística “suave”
, como consecuencia, los datos subyacentes que representan el quilate
y el precio
fueron modificados por la estadística, y la estadística sabía qué variables suavizar sobre la base de este mapeo estético.
Para un segundo ejemplo, veamos el stat “bin”
y el geom “bar”
, que juntos crean un histograma. La estadística “bin”
verifica el mapeo estético x
para determinar qué columna bin en recuentos discretos, y también crea algunas columnas completamente nuevas en los datos transformados por stats, incluida una llamada.. count..
. Los puntos extra indican al usuario que la columna producida por la estadística es novedosa. El geom “bar”
presta atención a la estética x
(para determinar la ubicación de cada barra en el eje horizontal) y la estética y
(para determinar la altura de cada barra).
El resultado de trazar lo anterior se muestra a continuación a la izquierda. Para completar el ejemplo, a continuación a la derecha se muestra la misma parcela con geom = “punto”
. Podemos ver fácilmente que los datos transformados por stats contienen solo alrededor de 30 filas, con columnas para centros de bin (quilates
mapeados en x
) y recuentos (.. count..
). La estadística “bin”
también genera una.. densidad..
columna que puedes explorar.
Valores predeterminados inteligentes, funciones de capa especializadas
La mayoría de nosotros probablemente estamos familiarizados con los tipos de parcelas estándar: histogramas, gráficas de líneas ajustadas, diagramas de dispersión, etc. Por lo general, el mapeo estadístico utilizado determinará el tipo de parcela común y el geom a usar. Por ejemplo, una estadística de agrupamiento probablemente vaya con un geom de barra para producir un histograma, y el geom de punto se empareja más comúnmente con el estadístico de identidad. (De hecho, en versiones anteriores de ggplot2
, si no se especificaba un stat o geom
en la llamada a layer ()
, se usaba un valor por defecto sobre la base del otro. Las versiones más recientes requieren que se especifiquen tanto geom =
como stat =
al llamar a layer ()
.) Del mismo modo, cuando se utiliza una estadística de binning, el mapeo estético y
por defecto es.. count..
si no se especifica.
Debido a que es muy común especificar una gráfica especificando el mapeo estadístico a usar, ggplot2 ()
proporciona funciones de capa especializadas que efectivamente mueven la especificación de la estadística al nombre de la función y usan el geom predeterminado (aunque aún se puede cambiar). Del mismo modo, a menudo deseamos especificar una gráfica por el tipo de geom y aceptar la estadística predeterminada para ese geom (aunque, nuevamente, esto se puede cambiar agregando un parámetro stat =
). Aquí hay dos formas más de trazar el histograma izquierdo de arriba:
(Hay una función de capa geom_bar ()
, pero su defecto no es el estadístico de binning; de ahí el geom_histograma alternativo ()
.) Para reproducir la parcela de arriba a la derecha, podríamos usar stat_bin (data = diamantes, mapping = aes (x = quilates), geom = “punto”)
.
Con tantos valores predeterminados establecidos, los comandos de trazado pueden llegar a ser bastante pequeños. Estas funciones de capa especializadas representan los métodos más utilizados para trazar en ggplot2
, siendo flexibles y rápidos.
Otro ejemplo de los valores predeterminados que se están estableciendo es la función de capa geom_boxplot ()
, que utiliza un geom “boxplot”
(una caja con bigotes) y una estadística predeterminada “boxplot”
El geom boxplot reconoce una serie de estéticas para las diversas piezas que posicionan la caja y los bigotes, incluyendo x
, y
, medio
, superior
, inferior
, ymin
e ymax
. Afortunadamente, la mayoría de estos valores requeridos son creados por la estadística boxplot y se establecen en consecuencia (al igual que los valores estéticos y
predeterminados en.. count..
para histogramas); solo se requieren las estéticas x
e y
para determinar las otras.
Hemos mapeado una variable discreta a x
y una variable continua a y
, ¡una gráfica de caja tendría mucho menos sentido al revés! También hay una función de capa correspondiente stat_boxplot ()
, que especifica el stat y usa el geom correspondiente predeterminado (boxplot).
Hasta ahora, hemos estado especificando individualmente los parámetros data =
y mapping =
para cada capa. Es común verlas establecidas solo una vez en la llamada a ggplot ()
, en cuyo caso se heredan para todas las capas posteriores. También podemos dejar fuera los datos =
y mapping =
nombres si primero especificamos los datos.
La mayoría de los usuarios de ggplot2
prefieren utilizar muchos de estos ajustes y valores predeterminados “fall-through”, aunque especificaremos todos los datos y asignaciones para cada capa para mayor claridad. (Y sí, diferentes capas pueden usar diferentes marcos de datos para sus datos =
parámetro).
Hay muchas funciones de capa especializadas para estadísticas y geoms específicos. La documentación para ellos y otras características de ggplot2
se puede encontrar en docs.ggplot2.org.
Ejercicios
- Utilice la función Base-R
plot ()
para producir una gráfica PDF que tenga el siguiente aspecto:
Hay 1,000 x valores distribuidos aleatoriamente (y uniformemente) entre 0 y 100, y los valores y siguen una curva definida por ellog ()
de x además de algo de ruido aleatorio. - La función
hist ()
de R es una forma conveniente de producir un histograma rápido. Intente ejecutarhist (rnorm (1000, media = 0, sd = 3))
. Lea la ayuda dehist ()
para determinar cómo aumentar el número de “bins”. - Utilice la función
layer ()
enggplot2
para producir un histograma de los precios de los diamantes. A continuación, intente usargeom_histogram ()
ystat_bin ()
. Para estas últimas parcelas, intente cambiar el número de bins del valor predeterminado de 30. - Intente crear una gráfica de puntos de diamantes (punto geom, estadística de identidad) usando
layer ()
conx
mapeado alcolor
e ymapeado
alprecio
. ¿Qué sucede cuando cambias laposición
a“jitter”
? A continuación, agregue una capa de diagrama de caja encima de esta capa de trama de puntos.
Más Estética y Expresiones Matemáticas
La función de capa geom_point ()
merece una atención especial, no solo porque las gráficas de dispersión son un tipo de parcela particularmente útil para la exploración de datos, sino también porque podemos usarla para ilustrar más características del paquete ggplot2
. Desafortunadamente, las gráficas de dispersión tienden a sufrir problemas de “sobretrazado” cuando el número de puntos de datos es grande, como en ejemplos anteriores. Por ahora, vamos a sortear este problema generando un subconjunto aleatorio de 1,000 diamantes para graficar, colocando la muestra en un marco de datos llamado dd
.
Primero, la capa geom_point ()
acepta una serie de estéticas que también podrían ser útiles en otras situaciones.
El resultado es probablemente demasiada estética para mapear valores a partir de los datos, pero a veces con fines exploratorios (en lugar de publicación), esto no es malo. En esta trama podemos ver algunas características interesantes de los datos. (1) Los diamantes suelen ser cortados a tamaños en quilates que son números redondos (0.25, 0.5, 1.0, etc.). (2) El precio por quilate (mapeado al color) es generalmente mayor para los diamantes más grandes. Esto significa que no solo son más caros los diamantes más grandes, sino que también son más caros por quilate (son más raros, después de todo). (3) Aunque es un poco difícil de ver en esta trama, parece que los puntos con el mejor corte (mapeados a alfa, o “transparencia”) también son de profundidad intermedia ( mapeado al eje y). O, por lo menos, los valores atípicos en profundidad tienden a tener valores de “corte” más pobres.
Esta gráfica también ilustra que la estética generalmente se puede mapear a datos continuos o discretos, y ggplot2
manejará los datos con gracia. Además, podemos especificar los datos como expresiones matemáticas de las columnas en el marco de datos de entrada (o incluso otros datos), como hicimos con color = precio/quilate
. Hacerlo nos permite explorar conjuntos de datos de una manera potente y flexible. Podríamos discretizar rápidamente el precio por quilate fijando color = precio/quilate > 5000
, por ejemplo, o podríamos reducir el rango de estos valores trazando con color = log (precio/quilate)
. En la subsección sobre escalas, sin embargo, veremos que ggplot2
contiene algunas características amigables para trazar datos en escalas ajustadas al registro y escalas similares.
Debido a que esta trama está demasiado ocupada, vamos a arreglarla eliminando el mapeo alfa y tamaño, recordando la posibilidad de una relación entre corte y profundidad para futuras exploraciones. También agregaremos una capa para una línea de ajuste suavizado.
Las funciones de capa como layer ()
y geom_point ()
aceptan opciones adicionales además de datos
, stat
, geom
y mapeo
. En este ejemplo, la primera capa se vería mejor si fuera parcialmente transparente, de manera que la capa superior pudiera destacar. Pero no queremos mapear la estética alfa a una propiedad de los datos, solo queremos que la establezca en una constante para todos los geoms de la capa. Así podemos establecer alpha = 0.2
fuera del mapeo aes ()
como una opción para la propia capa. Del mismo modo, podríamos querer que nuestra línea de ajuste sea roja, y observamos de la documentación que la capa stat_smooth ()
toma un argumento de método
que se puede establecer; “auto”
es el valor predeterminado para un suave no lineal y “lm”
producirá un ajuste lineal.
Como nota general, ggplot2 impone
que todas las capas compartan las mismas escalas. Por esta razón, no quisiéramos trazar en una capa x = quilate, y = profundidad
y en otra x = quilate, y = precio
; todos los valores y
serán forzados en una sola escala, y debido a que la profundidad oscila hasta ~70 mientras que los precios van hasta ~18,000, los valores de profundidad serían indiscernible. Esto también se aplica a las asignaciones de color, si las utilizan varias capas.
El paquete ggplot2
hace cumplir estas reglas para facilitar la comprensión de las gráficas que utilizan múltiples capas. Por las mismas razones, ggplot2
no admite múltiples ejes y (es decir, un eje y “izquierdo” y un eje y “derecho”), ni admite de forma nativa gráficas tridimensionales que son difíciles de leer en una superficie bidimensional, como papel o un monitor de computadora. [4]
Facetado
El facetado es una de las técnicas que puede ser bastante difícil de hacer en otros paquetes gráficos, pero es fácil en ggplot2
. Las facetas implementan la idea de “pequeños múltiplos” que promueve Edward Tufte. [5] Diferentes subconjuntos de datos se trazan en paneles independientes, pero cada panel usa los mismos ejes (escalas), lo que permite comparaciones fáciles entre paneles. En ggplot2 ()
, podemos agregar una especificación de faceta agregando otra llamada a la función a la “cadena” de funciones de capa que definen la gráfica. El facetado casi siempre se realiza en columnas discretas del marco de datos de entrada, aunque a continuación se presentan algunas técnicas para discretizar columnas continuas.
La primera función facet-specification es facet_wrap ()
. Se necesita un parámetro requerido, tres parámetros menos utilizados pero ocasionalmente útiles, y algunos más que no discutiremos aquí.
- El primer parámetro es una fórmula que especifica las columnas del marco de datos de entrada para facetar por. Para
facet_wrap ()
, esta fórmula suele ser de la forma~
<column>, sin ninguna “variable” especificada a la izquierda de la~
. Si deseamos facetar en todas las combinaciones de múltiples columnas de entrada, podemos usar~ <column_1>+ <column_2>+...
. - El parámetro
nrow =
controla el número de filas de paneles que deben aparecer en la salida. - El parámetro
ncol =
controla el número de columnas de paneles que deben aparecer en la salida. (Los parámetrosnrow
timesncol
deben ser lo suficientemente grandes como para contener todos los paneles necesarios. Por defecto,nrow
yncol
se determinan automáticamente.) - El parámetro
scales =
se puede establecer en“fixed”
(el valor predeterminado), lo que especifica que todos los ejes deben escalarse de manera similar en los paneles. Establecer este parámetro en“free_x”
permite que los ejes x varíen entre los paneles,“free_y”
permite que los ejes y varíen, y“libre”
permite que ambas escalas varíen. Debido a que las facetas suelen estar diseñadas para permitir comparaciones entre paneles, en la mayoría de las situaciones se deben evitar ajustes distintos a los“fijos”
.
Volviendo a las parcelas de puntos de los datos de diamantes, recordemos que parecía haber alguna relación entre el “corte” y la “profundidad” de los diamantes, pero en las parcelas anteriores, esta relación era difícil de ver. Vamos a trazar lo mismo que arriba, pero esta vez faceta en la columna de corte.
El facetado de esta manera produce un panel separado para cada tipo de corte, todo en los mismos ejes, pero cualquier cosa específica de la gráfica (como las líneas de ajuste) se calcula de forma independiente. Esto revela que los diamantes de talla “ideal” tienden a tener una profundidad de alrededor de 62, mientras que los cortes de menor calidad se desvían de este valor. Para facetar en corte y color, la fórmula sería ~ cut + color
, y se crearía un panel para cada combinación de corte/color.
La función facet_grid ()
funciona de manera muy parecida a facet_wrap ()
pero nos permite facetear de acuerdo no a una sino a dos variables (o dos combinaciones de múltiples variables) simultáneamente. Una de las variables variará entre filas de paneles y la otra variará entre columnas. El primer parámetro sigue siendo una fórmula, pero generalmente de la forma ~
<column_1><column_2>. Reemplazemos el facet_wrap (~ cut)
por facet_grid (cut ~ color)
:
A medida que aumenta el número de facetas, la legibilidad puede disminuir, pero haber cortado a lo largo de las filas y el color a lo largo de las columnas ciertamente ayuda a revelar tendencias. En esta especificación facetaria, vemos que los diamantes “justos” son relativamente raros en el conjunto de datos, y los diamantes más grandes tienden a ser cortes premium o ideales en colores pobres (I y J). La producción de archivos PDF con dimensiones más grandes en ggsave ()
puede hacer que las gráficas con muchas características sean más legibles.
Al igual que facet_wrap ()
, facet_grid ()
puede tomar un parámetro scales =
para permitir que los ejes x e y del panel varíen, aunque de nuevo esto generalmente no es recomendable, ya que dificulta la comparación visual de los paneles. La función facet_grid ()
incluye otro parámetro opcional, margins =
, que cuando se establece en TRUE
agrega paneles “agregados” para cada columna y fila de paneles. Aquí está la trama con facet_grid (cut ~ color, margins = TRUE)
:
Al trazar una cuadrícula de facetas, también podemos usar un punto en la especificación para indicar que la cuadrícula debe consistir en una sola fila o columna de paneles. Si bien facet_wrap ()
también puede producir solo una fila o cuadrícula, la opción margins = TRUE
se puede usar con facet_grid ()
para producir una fila o columna mientras se produce simultáneamente un panel agregado. Aquí está la misma parcela con facet_grid (. ~ corte, márgenes = VERDADERO)
.
Las facetas generalmente se crean para diferentes valores de datos categóricos. ¡Un intento de facetar todos los diferentes valores en una columna continua podría resultar en millones de paneles! (O, más probablemente, una instancia estrellada de R.) Aún así, ocasionalmente queremos facetar sobre datos continuos produciendo “bins” discretizados individuales para valores. Considera si quisiéramos facetar el precio/quilate del diamante, categorizado como “alto” (al menos $10,000) o “bajo” (menos de $10,000). Desafortunadamente, las fórmulas tomadas por facet_wrap ()
y facet_grid ()
no permiten expresiones vectorizadas, por lo que facet_wrap (~ precio/quilates < 10000)
no funcionará.
La solución es crear primero una nueva columna del marco de datos antes de trazar, como en dd$price_carat_low <- dd$precio/dd$carat < 10000
, para crear una nueva columna lógica, y luego facetar en la columna recién creada con facet_wrap (~ price_carat_low)
.
R también incluye una función llamada cut ()
específicamente para discretizar vectores continuos en factores. El primer parámetro es el vector a discretizar, y el segundo parámetro es un número de bins (de igual tamaño) para dividir la entrada, o un vector de puntos de interrupción para los bins.
El cut ()
también puede tomar un parámetro labels =
, para los casos en que las etiquetas predeterminadas no son suficientes.
Básculas
Cada estética utilizada en una parcela está asociada a una escala, ya sea la x
e y
o incluso el color
o el tamaño
. Para las gráficas facetadas, generalmente cualquier ajuste de escala se comparte entre facetas, y para cada capa de una gráfica, todas las propiedades de escala deben compartirse también. Los diferentes tipos de escalas (continuas para x
e y
, valores de color para color
, tamaños para tamaño
) se pueden modificar para cambiar el nombre de la escala, el rango, la ubicación de las roturas (o marcas de selección) y las etiquetas de las roturas. Hay más que decir sobre las escalas de lo que se puede cubrir en este libro, pero intentaremos llegar a los puntos más altos.
En lugar de seguir trazando el conjunto de datos de diamantes, carguemos un marco de datos más relevante biológicamente. Esta tabla, almacenada en un archivo llamado contig_stats.txt
, resume las estadísticas de secuencia de un ensamblaje de genoma de novo. Cada fila representa un “cóntigo” del ensamblaje (una sola secuencia destinada a representar una pieza contigua de la secuencia del genoma producida a partir de muchas piezas secuenciadas superpuestas).
Cada cóntigo tiene un valor promedio_cobertura
, que representa el número promedio de lecturas de secuencia que cubren cada base en el cóntigo ensamblado. Estos valores pueden variar ampliamente, potencialmente debido a regiones duplicadas del genoma que se ensamblaron erróneamente en un solo cóntigo. La columna Consensus_length
indica la longitud del cóntigo (en pares de bases), y la columna gccontent
muestra el porcentaje de bases G o C del cóntigo.
Vamos a producir una gráfica de puntos para estos datos con Average_coverage
en el eje x
y consensus_length
en el y
.
El resultado no es muy bueno. Hay valores atípicos en ambos ejes, lo que nos impide ver alguna tendencia en los datos. Ajustemos la escala x
agregando una escala_x_continuous ()
, estableciendo name =
para fijar el nombre de la escala, y usando limits =
para establecer los límites de la escala en c (0, 1000)
. También usaremos el correspondiente scale_y_continuous ()
para establecer un nombre propio para el eje y. (Para escalas discretas, como en el ejemplo boxplot anterior, las funciones correspondientes son scale_x_discrete ()
y scale_y_discrete ()
.)
Esto es mucho mejor. Parece que la mayoría de los cóntigos más largos tienen una cobertura de aproximadamente 100X. Lamentablemente, esta estrategia deja fuera muchos grandes puntos de datos para mostrar las tendencias en la pequeña mayoría. En su lugar, deberíamos ajustar logarítmicamente los datos trazando aes (x = log (Average_coverage), y = consensus_length)
, o log-ajustar la escala. Si logarítmicamente ajustamos los datos, tendríamos que recordar que los valores están ajustados. Tiene más sentido modificar la propia escala y trazar los datos originales en la escala no lineal. Esto se puede hacer suministrando un parámetro trans =
a la escala y especificando el nombre de una función de transformación soportada para aplicarla a la escala como un vector de caracteres de un solo elemento. De hecho, hagamos que las escalas x
e y
se ajusten logarítmicamente. Mientras estamos en ello, especificaremos marcas de rotura explícitas para las escalas, así como etiquetas personalizadas para esas marcas de rotura.
El resultado está abajo a la izquierda, y se ve bastante bien. Para un flourish, podemos agregar un annotation_logticks (base = 10)
para obtener marcas de marca escaladas logarítmicamente, que se muestran abajo a la derecha.
Otras funciones de ajuste que podríamos haber usado para el parámetro trans =
incluyen “log2"
o “sqrt”
, aunque “log10"
es una opción común con la que la mayoría de los espectadores estarán familiarizados.
Uno de los problemas que quedan con nuestra trama es que hay demasiados puntos de datos para encajar en este pequeño espacio; esta trama tiene un problema de “sobretrazado”. Hay una variedad de soluciones para el sobretrazado, incluido el muestreo aleatorio, el establecimiento de la transparencia de los puntos o el uso de un tipo de parcela diferente en conjunto. Convertiremos esta trama en un tipo de mapa de calor, donde los puntos cercanos entre sí se agruparán en una sola “celda”, cuyo color representará alguna estadística de los puntos en esa celda. [6]
Hay dos funciones de capa que podemos usar para tal mapa de calor, stat_summary_2d ()
y stat_summary_hex ()
. El primero produce celdas cuadradas, y el segundo hexágonos. (La capa stat_summary_hex ()
requiere que tengamos el paquete “binhex”
instalado a través de install.packages (“binhex”)
en la consola interactiva.) Usaremos stat_summary_hex ()
, ya que es un poco más divertido. Esta función de capa requiere más del número habitual de parámetros y estética:
- Los
datos =
marco de datos a trazar (como de costumbre). - El
mapeo =
estética para establecer víaaes ()
(como de costumbre), requiriendox
, la variable a bin por en el ejex
;y
, la variable a bin por en el ejey
; yz
, la variable a celdas de color por. - Un parámetro
fun =
, especificando la función a aplicar a los valoresz
para cada celda para determinar el color.
Esto podría ser un poco confuso sin un ejemplo, así que reemplacemos la capa dotplot con una capa stat_summary_hex ()
que traza x
e y
de la misma manera, pero coloreando las celdas por la media gccontent
de puntos dentro de esa celda.
El resultado, abajo a la izquierda, tiene celdas coloreadas por la función media
aplicada a todos los valores gccontent
(desde la estética z
), pero no revela cuántos puntos están presentes en cada celda. Para ello, podemos usar fun = length
, que devuelve el número de elementos en un vector en lugar de la media, resultando en la gráfica de abajo a la derecha.
Al igual que las ubicaciones x
e y
en las escalas, los colores de las celdas también existen en una escala. En este caso, podemos controlarlo con el modificador scale_fill_gradient ()
. (Las líneas y otros colores no rellenos se controlan con scale_color_gradient ()
, y las escalas de color discretas se controlan con scale_fill_descrete ()
y scale_color_discrete ()
). Esto significa que las escalas de color pueden nombrarse, transformarse y recibir límites, roturas y etiquetas. A continuación, la cadena "#BFBCFF"
especifica el color púrpura claro en la parte superior de la escala, basado en el esquema de codificación de colores RGB.
También hemos incluido un ajuste trans = “log10"
en esta escala de colores, lo que indica que se puede transformar al igual que otras escalas continuas. Usar un ajuste log10
en una escala de colores puede ser o no una buena idea. Para este conjunto de datos, ilustra más claramente la distribución de cóntigos en el espacio trazado, pero dificulta las comparaciones entre celdas y con la leyenda.
El sistema de color RGB
RBG significa rojo, verde, azul. Los monitores de computadora y otros dispositivos digitales muestran colores por las intensidades variables de pequeños dispositivos emisores de luz roja, verde y azul. Un triplete de estos constituye un solo píxel en la pantalla. El esquema RGB codifica un color como #
<RR><GG><BB>, donde <RR>codifica la cantidad de luz roja,
<GG>la cantidad de verde y
<BB>la cantidad de azul. Estos valores pueden oscilar entre
00
(off) y FF
(completamente encendido); estos son números codificados en formato hexadecimal, lo que significa que después del 9
, el siguiente dígito es A
, luego B
, y así sucesivamente, hasta F.
(Contando desde 49
, por ejemplo, los siguientes números son 4A
, 4B
,. 4F
, 50
, 51
, etc.) ¿Por qué rojo, verde y azul? La mayoría de los humanos tienen tres tipos de células cónicas en sus ojos, ¡y cada uno es más sensible a la luz roja, verde o azul! Por lo tanto, un esquema RGB puede representar casi todos los colores que los humanos pueden ver, aunque al final estamos limitados por las gradaciones (el <RR><GG><BB>formato #
solo puede tomar alrededor de 16.7 millones de valores diferentes) y la calidad de los dispositivos emisores de luz (muchos de los cuales no pueden producir luz muy brillante o estar completamente apagado en funcionamiento). El daltonismo es una anomalía genética causada por tener solo uno o dos de los tres tipos de cono, y unos pocos individuos raros pero afortunados poseen cuatro tipos de cono junto con una mayor agudeza en la visión del color (tetracromacia).
Algo a tener en cuenta al diseñar escalas de color es que no todas se crean por igual: un porcentaje justo de espectadores tendrá algún tipo de daltonismo, y otro porcentaje justo de espectadores preferirá imprimir una trama en una impresora en blanco y negro. La función scale_color_brewer ()
ayuda al usuario a seleccionar buenas paletas de colores; se basa en el trabajo encontrado en colorbrewer2.org. Otros tipos de escala se pueden ajustar de manera similar, incluyendo alfa (transparencia) y los tamaños de puntos y líneas.
Coordenadas
Además de modificar las propiedades de las escalas, también podemos modificar cómo se interpretan esas escalas en la parcela general y en relación entre sí. Algunas de las modificaciones de coordenadas son menos comunes, pero otras (como coord_equal ()
, abajo) son útiles. A menudo, los ajustes de coordenadas se ilustran considerando una gráfica de puntos o una gráfica de barras en coordenadas polares.
La función coord_polar ()
requiere un parámetro theta =
para indicar qué eje (x
o y
) se debe mapear al ángulo de rotación; el eje restante se mapea al radio. Esta modificación de coordenadas se puede utilizar para producir parcelas interesantes, especialmente cuando el geom utilizado es “barra”
o “línea”
.
La función coord_flip ()
se puede utilizar para voltear los ejes x
e y
. Esta característica es especialmente útil cuando el deseo es producir un histograma horizontal o un diagrama de caja.
Al establecer la estética de relleno
, las barras secundarias se apilan, que es la predeterminada. Para una gráfica con barras presentadas lado a lado, se puede agregar el argumento position = “dodge”
a la llamada a la capa geom_bar ()
.
Para un último ajuste de coordenadas, los valores mapeados a los ejes horizontal y vertical a veces son directamente comparables, pero el rango es diferente. En nuestra submuestra aleatoria de diamantes dd
, por ejemplo, las columnas x
y z
se miden ambas en milímetros (representando el “ancho” y la “altura” del diamante), pero los valores z
son generalmente más pequeños. A modo de ilustración, una sola unidad en el eje horizontal debe tener el mismo tamaño que una sola unidad en el eje vertical, pero ggplot2
no garantiza dicho tamaño por defecto. Podemos especificar el tamaño agregando un ajuste de coordenadas coord_equal ()
.
Observe que sin coord_equal ()
en la izquierda anterior, los tamaños de los ejes no son del todo comparables, pero las marcas de cuadrícula son cuadrados perfectos en la parte superior derecha. El ajuste coord_equal ()
también se puede hacer con parcelas ajustadas logarítmicamente, y a veces puede producir una salida más agradable incluso si los dos ejes no están en las mismas unidades. Aquí hay una comparación con y sin coord_equal ()
aplicada a la versión final de la gráfica de longitud contra cobertura del cóntigo anterior.
Como siempre, hay una serie de otros ajustes de coordenadas que son posibles, y solo hemos cubierto algunos de los más útiles o interesantes. Consulte docs.ggplot2.org para obtener la documentación completa.
Tematización, anotaciones, texto y fluctuación
Hasta ahora, hemos cubierto la personalización de cómo se trazan los datos y se representan los ejes/coordenadas, pero no hemos tocado las propiedades “auxiliares” de la trama como títulos, colores de fondo y tamaños de fuente. Estos son parte del “tema” de la trama, y muchos aspectos del tema son ajustados por la función theme ()
. La excepción es la adición de un título a una trama, que se logra con la función ggtitle ()
.
Las partes basadas en texto de una trama están organizadas jerárquicamente (ver la documentación para theme ()
para ver la lista completa). Por ejemplo, al modificar el parámetro text =
se modificarán todos los elementos de texto, mientras que al modificar axis.text =
se ajustan las etiquetas de tick a lo largo de ambos ejes, y axis.text.x =
especifica las propiedades de solo las etiquetas de tick del eje x. Otros elementos text-theme incluyen legend d.text
, axis.title
(para nombres de ejes), plot.title
y strip.text
(para etiquetas de facetas).
Para ajustar las propiedades de estos elementos, utilizamos una llamada a element_text ()
dentro de la llamada a theme ()
. Podemos producir una trama rápida contando diamantes por su corte y claridad, por ejemplo, estableciendo un título de trama y cambiando el tamaño general del texto a 16
, y solo el tamaño del título a 20
. Reducir el texto puede ser especialmente útil para los casos en que las etiquetas facetarias o las etiquetas temáticas son demasiado grandes para adaptarse a sus respectivas cajas.
Las etiquetas utilizadas para los descansos a veces son más largas de lo que caben cómodamente en los ejes. Aparte de cambiar su tamaño, a veces ayuda a inclinarlos 30 o 45 grados. Al hacerlo, también se ve mejor establecer hjust = 1
para justificar a la derecha las etiquetas.
Como podría sugerir este ejemplo, la tematización es en sí misma un tema complejo dentro de ggplot2
, y hay muchas opciones y funciones internas especiales que modifican casi todos los aspectos de una trama.
Aunque ggsave ()
acepta parámetros width =
y height =
especificando el tamaño general del archivo de salida, debido a que estos parámetros incluyen las etiquetas de leyenda y eje, la región de trazado tiene su relación de aspecto determinada automáticamente. Indicar que la región de trazado debe tomar una relación de aspecto específica (definida como la altura de la región sobre el ancho) también ocurre dentro de una llamada theme ()
.
El lector observador pudo haber notado que, por defecto, todas las regiones de trazado en ggplot2
utilizan un fondo gris claro. Esto es intencional: la idea es que una trama con fondo blanco, cuando se incrusta en un manuscrito, deje un “agujero” visual, interrumpiendo el flujo del texto. El tono de gris elegido para el fondo predeterminado está destinado a mezclarse con el tono general de una columna de texto.
Algunos usuarios prefieren usar un fondo blanco más tradicional, pero hacerlo requiere ajustar múltiples elementos, incluido el fondo en sí, las líneas de cuadrícula, etc. Entonces, ggplot2
incluye una serie de funciones que pueden cambiar el tema general, como theme_bw ()
.
Debido a que las llamadas a theme_bw ()
et al. modifican todos los elementos temáticos, si queremos modificar también elementos temáticos individuales con theme ()
, esos deben agregarse a la cadena después de la llamada a theme_bw ()
.
Una característica de ggplot2
aún no cubierta es el uso de texto dentro de las gráficas, que no son ajustes de tema sino tipos especiales de capas de trazado. La función de capa geom_text ()
facilita la creación de “dotplots” donde cada punto está representado por una etiqueta de texto en lugar de un punto. Aquí hay un ejemplo trazando los primeros 30 diamantes por quilate y precio, etiquetados por su corte.
En el resultado (abajo a la izquierda), es difícil ver que en algunos casos se trazan múltiples diamantes en la misma ubicación. Este tipo de sobretrazado también puede ocurrir con puntos; agregar una opción position = “jitter”
a la capa geom_text ()
modifica ligeramente la ubicación de todos los geoms para que destaquen (abajo a la derecha).
Varias estéticas del texto se pueden mapear a valores de los datos, incluyendo tamaño
, ángulo
, color
y alfa
. Al igual que con otras capas, para cambiar el tamaño de fuente (u otra propiedad) para todos los puntos a un valor constante, la instrucción debe darse fuera de la llamada aes ()
.
Las etiquetas de texto individuales, así como segmentos de línea individuales, rectángulos, puntos y otras geomas, se pueden agregar con una capa annotate ()
. Tal capa toma como primer argumento el nombre del geom que se agregará, y posteriormente cualquier estética que deba establecerse para ese geom (sin una llamada a aes ()
). Aquí hay una ilustración, terminando el ejemplo anterior de la trama longitud/cobertura. (El hjust = 0
en la anotación de texto indica que el texto debe estar justificado a la izquierda con respecto a la referencia x
e y
.)
Idealmente, nos esforzaríamos por producir gráficos listos para la publicación con código bien documentado y fácilmente editable. En algunos casos, sin embargo, los ajustes o anotaciones se agregan más fácilmente en programas de edición gráfica como Adobe Photoshop o Illustrator (o alternativas de código abierto como Inkscape), siempre y cuando no se altere la interpretación y el significado de los datos.
Ejercicios
- Utilice
ggplot2
para explorar eltrio.sample.vcf
que analizamos en capítulos anteriores. ¿Se puede visualizar de manera efectiva la distribución de las ubicaciones de SNP a través de los cromosomas? - Al ejecutar la función
data ()
(sin parámetros) en la consola interactiva R se enumerarán los conjuntos de datos incorporados que están disponibles. Por ejemplo,USArrestes describe estadísticas de arrestos
en estados de Estados Unidos en 1973, con columnas para tasas per cápita de asesinato, violación y asalto, y también una para el porcentaje de residentes estatales en áreas urbanas (verayuda (USArrestos)
para más detalles).Primero, vea si puede reproducir esta trama, donde hay una faceta para cada estado, y una barra para cada tipo de delito: Es posible que primero deba manipular los datos creando una columna para nombres de estados (en lugar de usar los nombres de fila) y “reuniendo” algunas de las columnas con
tidyr
.A continuación, vea si se puede reproducir la trama, pero de tal manera que los paneles estén ordenados por la tasa global de criminalidad (Asesinato + Violación + Asalto).
- Encuentra al menos otra forma de ilustrar los mismos datos. Entonces, encontrar la manera de incorporar en la visualización el porcentaje de población de cada estado en las zonas urbanas.
- Genera un conjunto de datos mediante observación o experimentación, ¡y visualízalo!
- La idea de una gramática gráfica fue introducida por primera vez en 1967 por Jacques Bertin en su libro Semiologie Graphique (París: Gauthier-Villars, 1967) y posteriormente ampliada en 2005 por Leland Wilkinson et al. en The Grammar of Graphics (Nueva York: Springer, 2005). Hadley Wickham, “A Layered Grammar of Graphics”, Journal of Computational and Graphical Statistics 19 (2010): 3—28, describió originalmente la implementación de R.
- Dada la información de capítulos anteriores sobre objetos, es posible que haya adivinado que el tipo de objeto devuelto por
ggplot ()
es una lista con conjunto de atributos de clase, donde la clase se establece en“gg”
y“ggplot”
. Además, se define un método`+.gg` ()
especializado para los objetos de la clase“gg”
, y+
no es solo azúcar sintáctico para`+` ()
, sino también una función genérica que se envía! - Si estás leyendo esto en blanco y negro, entonces tendrás que confiar en que los colores diferencien los puntos. Más adelante discutiremos la importancia de elegir esquemas de color que funcionen tanto en escala de grises como para lectores daltónicos, aunque aún no hemos cubierto los conceptos de código por hacerlo.
- Sin embargo, podemos explorar rápidamente datos multidimensionales mediante el uso de estéticas adicionales como el color, el tamaño, la forma, el alfa, etc. Si se requieren múltiples ejes y o gráficas tridimensionales, algunos otros paquetes R pueden proporcionar estas características, al igual que la utilidad de línea de comandos
gnuplot
. - Muchos en la comunidad de visualización de datos consideran los libros de Tufte, especialmente The Visual Display of Quantitative Information (Cheshire, CT: Graphics Press, 1983), como elementos básicos. Estos volúmenes son hermosos por derecho propio como ejemplos de presentación de información.
- Estas funciones se pueden utilizar para crear mapas de calor, pero generalmente las filas y columnas de un mapa de calor se pueden ordenar de diferentes maneras. Muchos paquetes están disponibles para trazar mapas de calor de diversos tipos en R, quizás uno de los más interesantes es el paquete
NeatMap
, que se basa enggplot2
.