Los gráficos e infografías son, cada vez más, una parte importante de la mayoría de textos escritos, ya sean estos un informe técnico, un artículo de periódico o un TFG. En el caso de la ciencia de datos, como puede verse abajo en la infografía, el análisis y la exploración de los datos es un proceso iterativo en el que la visualización y la generación de gráficos ocupa un lugar destacado.
R for Data Science (http://r4ds.had.co.nz/)
Uno de los instrumentos y tareas fundamentales de un científico de datos es la capacidad de realizar visualizaciones de datos apropiadas y convincentes. El análisis gráfico no solo ayuda en la exploración y comprensión de los datos, sino que es fundamental a la hora de mostrar las posibles relaciones entre variables, descubrir relaciones o patrones ocultos, y descartar o sugerir nuevas preguntas sobre los datos.
El entorno R tiene diversos sistemas para visualizar datos, los dos
más utilizados son el sistema gráfico de R-base y el ecosistema asociado
al paquete ggplot2. Por diversas razones, en el curso
usaremos el entorno ggplot2 para hacer nuestros gráficos;
de hecho, en la actualidad ggplot2, dada su rapidez en la
iteración entre gráficos, versatilidad y la cuidada estética que tienen
sus gráficos, se ha convertido, al menos por el momento, en el sistema
estándar para hacer gráficos en R. Por ejemplo, ¿cómo creéis que hace la BBC sus gráficos?,
evidentemente con R y ggplot2. Puedes ver uno de sus
repositorios aquí y su cookbook aquí.
Con ggplot2 es sencillo hacer gráficos con calidad para
ser publicados o mostrados, además de que, dada su sintaxis modular,
hace sencillo el reutilizar los gráficos durante el proceso de análisis.
El paquete ggplot2 fue inicialmente desarrollado por Hadley Wickham, pero
actualmente el ecosistema ggplot es el resultado de toda una comunidad
de usuarios que contribuye a enriquecer el sistema gráfico con sus
extensiones y paquetes auxiliares.
En palabras de Hadley en su libro sobre ggplot2:
ggplot2 is an R package for producing statistical, or data, graphics, but it is unlike most other graphics packages because it has a deep underlying grammar. This grammar, based on the Grammar of Graphics (Wilkinson 2005), is made up of a set of independent components that can be composed in many different ways. This makes ggplot2 very powerful because you are not limited to a set of pre-specified graphics, but you can create new graphics that are precisely tailored for your problem. This may sound overwhelming, but because there is a simple set of core principles and very few special cases, ggplot2 is also easy to learn (although it may take a little time to forget your preconceptions from other graphics tools).
Sí, con ggplot2 es “fácil” hacer rápidamente gráficos de
calidad, PERO dominar todos los detalles del paquete sí que es
complicado, pero no nos hace falta conocerlo todo. Además, hay que tener
en cuenta que ggplot2 es un paquete/entorno en constante
evolución. Actualmente está en la versión 3.2.1. Bueno, en marzo de 2020
apareció la versión 3.3.0.
Para entender esta idea de la constante evolución y el papel que
tiene la comunidad de usuarios en el desarrollo de R y sus paquetes
puedes leer este tweet y las respuestas a él. En el tweet sólo
se anuncia una pequeña mejora en como ggplot2 gestiona los
títulos de los gráficos pero genera reacciones en la comunidad de
usuarios.
La redes sociales pueden hacerse eco de la evolución de un paquete,
pero donde habitualmente se produce la discusión/colaboración entre
usuarios es en plataformas como Github. Por ejemplo, puedes ver como se gestó está
pequeña mejora aquí. Fue la issue 3252 de ggplot2.
Otro ejemplo, justo cuando estaba escribiendo este párrafo, leí este otro tweet anunciando otra mejora en
ggplot2.
La página web de ggplot2 puedes encontrarla aquí. En ella
puedes encontrar documentos de ayuda y la referencia oficial. Para darte cuenta de todo lo que
se puede hacer con el ecosistema ggplot visita esta
página donde podrás ver los 79 “paquetes auxiliares” o extensiones a
ggplot2.
Para hacer “buenos” gráficos con ggplot2no sólo es
necesario entender la sintaxis y los pormenores del paquete, sino que
quizás se necesite algo más. Por ejemplo, algo de experiencia y cierta
capacidad visual y estética; incluso hay quien dice que hacer buenos
gráficos es un arte. Para intentar mejorar vuestros gráficos o evitar
ciertos errores, aquí tenéis algunas reglas/consejos, y aquí un curso completo sobre visualización1 con bookdown
incluido.
Entenderás muy bien que hacer buenos gráficos exige conocimiento y mucho trabajo al ver el video de este post, donde se ven las versiones previas para que al final saliese esta preciosura de gŕafico:
@LeTour for this #TidyTuesday. I recreated and adapted the main plot from @ffranchi's great infographic: https://t.co/qLZgLS6jUo
— Georgios Karamanis (@geokaramanis) April 7, 2020
code and big image: https://t.co/ns6qngDdJX#dataviz #rstats pic.twitter.com/DKSYks4j1v
Otro ejemplo del making-of de un gráfico puedes verlo aquí.
Otros dos libros sobre visualización con el código de los ejemplos
hechos con ggplot2, aquí y aquí. Finalmente, algunos consejos de la BBC sobre
visualización.
Como también se aprende los errores, aquí tienes un articulo de The Economist donde muestran errores que ellos mismos han cometido haciendo gráficos. Además pueden descargarse los datos.
Ya se dijo que ggplot2 es un paquete R desarrollado por
Hadley Wickham, aunque actualmente es el resultado de la colaboración de
múltiples desarrolladores. ggplot2 implementa en R The Grammar of
Graphics de L. Wilkinson, un sistema coherente para describir y
construir gráficos. El énfasis de ggplot2 está en la exploración rápida
de datos, especialmente de datos de alta dimensionalidad. Con
ggplot2 es sencillo ir transformando el gráfico mientras se
van analizando los datos.
Para empezar a entender la “filosofía” de ggplot2, os
planteo una pregunta medio retórica: ¿qué vemos en el gráfico de
abajo?
Pues sí, es un gráfico de puntos y nos ayuda a ver las relaciones que
existen entre 3 variables. Estamos habituados a ello, pero vamos a
pensar en el gráfico desde la óptica de “The Grammar of Graphics”
implementada en el paquete ggplot2.
En nuestro gráfico se representan por medio de puntos, en el espacio
X-Y, y mediante los distintos colores de los puntos, las observaciones
de 3 variables. Bien, nada muy novedoso, todos los sistemas gráficos
hacen este tipo de gráficos. Los gráficos de ggplot2 se
realizan mediante la superposición de elementos/capas. Podemos pensar
que el gráfico que hemos visto es una capa. ¿Cómo creamos este gráfico o
capa en ggplot2?
Pues, una de las principales ideas para entender ggplot2
es que cada capa de un gráfico tiene 3 componentes o elementos
principales:
los datos que se van a representar (sencillo,
para hacer un gráfico hacen falta datos). Para ello utilizaremos
generalmente la función ggplot()
un conjunto de propiedades estéticas asociadas a alguna
variable del conjunto de datos. Por ejemplo, la variable
Sepal.Lenght está asociada al eje X, ala posición en el eje X. Por su
parte, el color de los puntos (otra característica visual o estética)
está asociado a los valores de la variable Species. Es decir, usando la
terminología de ggplot2, las distintas variables están
asociadas o mapeadas a determinadas características estéticas. El mapeo
de variables con estéticas se hará con la función aes() de
aesthetics. (esto ya no es tan estándar, se explica en
breve)
el elemento geométrico que se va a representar.
En nuestro caso el elemento geométrico que se utiliza para representar
los valores de las variables son los puntos, pero podrían haber sido las
lineas o las barras … Para especificar el elemento geométrico que vamos
a usar en nuestro gráfico se utiliza la familia de funciones
geom_xx(); por ejemplo geom_point() si
queremos puntos, geom_line() si queremos que las relaciones
entre las variables se representen/visualicen como lineas.
Así en abstracto puede ser complicado entender del todo que quiere
decir todo esto. Vamos a verlo con ejemplos concretos. De momento, para
explicar las principales características de ggplot2
utilizaré un conjunto de datos famoso, pero odiado por algunos, por
haber sido utilizado en numerosos ejemplos y cursos: el iris
dataset.
El conjunto de datos iris contiene datos sobre 150
flores, en concreto sobre 150 lirios. iris tiene 5
variables, 4 de ellas miden la longitud y el ancho del pétalo y sépalo
de los 150 lirios. Estas 4 primeras variables son cuantitativas y
continuas; mientras que la quinta variable es categórica, indicando la
clase o variedad de los lirios, ya que en los datos hay 3 especies
distintas de lirios (setosa, versicolor y virginica). Con estos datos,
con 3 de sus variables, se ha creado el gráfico que ves más arriba.
PRIMER GRÁFICO: Para comenzar nuestras andanzas con
ggplot2 intentaremos replicar con código R el gráfico de
arriba; aunque al principio sólo utilizaremos 2 variables: haremos un
gráfico de puntos de la longitud del sépalo frente a la longitud del
pétalo.
Hacer un gráfico con ggplot2 requiere de varias
etapas,
la primera de ellas consiste en usar la función
ggplot() para inicializar el gráfico.
en segundo lugar, tendremos que especificar que conjunto de datos usaremos en el gráfico.
en tercer lugar tendremos que especificar que variables irán asociadas a determinados elementos visuales o estéticos del gráfico
por último, en cuarto lugar, tendremos que especificar que tipo de gráfico o geometría usaremos para visualizar las observaciones.
Veámoslo más detenidamente.
En ggplot2, para hacer un gráfico se empieza
SIEMPRE llamando a la función ggplot(). Si
tecleamos ggplot() en la consola o en un script, parece que
no ocurre nada, pero tras la llamada a la función ggplot(),
R ha creado un objeto, un contenedor para nuestro futuro gráfico. Aún no
vemos el gráfico, faltan cosas, pero ya lo hemos inicializado. Si
quieres ver el objeto/contenedor que hemos creado con la llamada a
ggplot() tienes que asignarle un nombre, así podrás verlo
en la pestaña “Environment” de RStudio.
Para verlo tienes que hacer:
my_grafico <- ggplot()
my_grafico, es un objeto R, concretamente una lista con
9 elementos, que tendremos que ir “llenando” para hacer nuestro
gráfico.
Generalmente, dentro de la función ggplot() se suele
especificar el conjunto de datos que vas a utilizar para hacer el
gráfico. A diferencia de los gráficos de R-base, ggplot2 no
permite graficar vectores: los datos que se suministran han de
ser SIEMPRE data.frames o similares.
ggplot(data = iris)
ggplot(iris)
Ya está, con cualquiera de las 2 instrucciones de arriba, son equivalentes2, ya hemos inicializado el gráfico y le hemos dicho que datos vamos a usar.
Dijimos que para comenzar haríamos un gráfico de puntos de la
variable Sepal.Length frente a Petal.Length;
así que tenemos que decirle a ggplot2 que variables
de iris queremos visualizar y con que propiedades estéticas
queremos asociar cada variable. Para ello utilizaremos la
función aes() dentro de ggplot(). Lo hacemos
con la siguiente expresión:
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length))
Aún no vemos el gráfico, pero con aes() le hemos dicho a
R/ggplot2 que queremos asociar/mapear la variable Sepal.Length al eje x,
y la variable Petal.Length al eje y. Fíjate que, en la pestaña de
gráficos de RStudio, ya vemos los ejes del gráfico; además, fíjate que
ggplot2 ya ha calculado para nosotros el rango de las
variables para ajustar los ejes.
Al igual que antes, podemos omitir los nombres de las opciones de la
función aes(). Esta función puede tener muchos argumentos
(veremos algunos), pero los 2 primeros son siempre x (el eje x) y
después y (el eje y o vertical de mi gráfico); es decir podríamos hacer
lo siguiente que es más rápido de teclear.
ggplot(iris, aes(Sepal.Length, Petal.Length))
Con esta instrucción le estamos diciendo a ggplot2 que
vamos a hacer un gráfico con los datos del data.frame iris
y que vamos a asociar/conectar/mapear la variable
Sepal.Length con el eje x, y la variable
Petal.Length con el eje y del gráfico. Perfecto, pero
entonces ¿por qué no vemos el gráfico? La razón estriba en que no le
hemos dicho a ggplot2 qué tipo de gráfico queremos (de
puntos, de lineas etc…). El tipo de gráfico se explicita con una familia
de funciones: geom_xx() o geometrías. Hay
muchas geometrías o tipos de gráficos que podemos usar. Ya lo veremos!!!
Nosotros queremos hacer un gráfico de puntos, así que, de la familia de
geometrías tenemos que usar geom_point().
Veámoslo.
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
Como vemos los puntos del gráfico se visualizan en color negro, con
un tamaño, una transparencia y una forma determinadas. Obviamente todo
esto se puede cambiar dentro de geom_point() con las
opciones adecuadas. Por ejemplo:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(color = "red", size = 2, alpha = 0.2)
Ya casi está. No es tan complicado. Ya hemos visto las ideas
fundamentales de la visualización con ggplot2:
Los gráficos se inician con la función ggplot().
Generalmente aquí se especifican los datos (data.frame) que queremos
utilizar
La función aes() sirve para asociar/mappear
variables con atributos/características estéticas del gráfico. De hecho
el nombre del función aes() viene de
aesthetics. Las aesthetics más
importantes de un gráfico suelen ser los ejes x e y, por eso se ponen
siempre al principio de aes(); es decir, son los 2 primeros
argumentos de aes(). En nuestro ejemplo hemos asociado la
variable Sepal.Length con el eje x, y la variable
Petal.Length con el eje y. Veremos más
aesthetics, como por ejemplo el color o el tamaño (de
los puntos … o de las lineas o …)
Con geom_**() elegimos el tipo o
geometría de gráfico. Hay muchos tipos de gráficos, así
que habrán muchos geoms. Por ejemplo: geom_point(),
geom_line(), geom_ …
Estas 3 ideas son las principales para entender ggplot2. Después hay muchas más opciones y elementos que serán muy importantes para conseguir un buen gráfico, pero en cierta forma son secundarias; por ejemplo, los títulos, los ejes, las escalas, el tema etc… lo iremos viendo poco a poco.
Afiancemos las ideas principales de la visualización con
ggplot2. ¿Piensa que hará la siguiente linea de código?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_line()
La primera parte de la instrucción es igual a la anterior: queremos un gráfico con el data.frame iris y queremos asociar la variable Sepal.Length con el eje x, con la propiedad aesthetic eje x y Petal.Length con el eje y; pero le hemos pedido un gráfico de lineas (geom_line()). En este caso hacer un gráfico de lineas no tiene mucho sentido, pero si se lo pedimos a R, este nos hace caso y nos lo muestra.
Ya dije que una de las características importantes de
ggplot2 es que funciona por capas que se van superponiendo;
para ir añadiendo capas a nuestro gráfico tenemos que usar el símbolo
+. Por ejemplo si quisiéramos ver los
puntos y las lineas ¿Cómo lo hacemos?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_line()
Tampoco son muy útiles la lineas en este gráfico.
Otra geometría o geom_() que se usa mucho es
geom_smooth(). Probémosla:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth()
Del gráfico puede inferirse que hay una relación, no lineal, pero sí
directa o positiva entre la longitud del sépalo y del pétalo; pero
también se aprecia que hay al menos dos grupos distintos de lirios. Hay
un grupo de observaciones cuyo pétalo parece ser claramente menor que el
del resto de lirios. Veamos si esto se debe o esta asociado al tipo de
lirio, recuerda que hay 3 tipos de lirios, asociados a la variable
iris$Species. Para verlo en nuestro gráfico lo que vamos a
hacer es asociar/mapear la variable Species con la
aesthetics color:
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point()
Pues parece que sí, que la especie de lirios “setosa” es más pequeña, al menos en longitud, del sépalo, pero sobre todo del pétalo.
La variable Species podríamos haberla asociado a la
estética tamaño (size), o a la estética forma (shape) pero no sería tan
útil ni quedaría tan bonito el gráfico. Fíjate que incluso R nos avisa
de que asociar la propiedad o aesthetic tamaño con una
variable categórica como Species no es muy recomendable.
ggplot(iris, aes(Sepal.Length, Petal.Length, size = Species)) + geom_point()
#> Warning: Using size for a discrete variable is not advised.
También podemos asociar la variable Species a la
estética “forma”(shape). Lo hacemos en la expresión de más abajo. Como
veis, ahora las diferencias entre especies de lirios no se aprecian tan
bien como cuando usábamos color = Species
ggplot(iris, aes(Sepal.Length, Petal.Length, shape = Species)) + geom_point()
Os va a costar hacer gráficos, normal!!!, pero espero que la idea principal ya la tengáis. Lo que pasa es que no os he contado todo, en realidad es un poco más complejo y versátil. Lo medio explico en el siguiente apartado.
Ya tenéis las ideas principales para hacer gráficos con
ggplot2, pero no os lo he contado todo, tampoco lo voy a
hacer ahora, pero si contaré las cosas de una forma diferente para que
tengáis más flexibilidad/versatilidad a la hora de hacer gráficos. Si
queréis saber toda la verdad3 tendréis que ir al libro de Hadley,
concretamente aquí.
La forma que os he contado de hacer gráficos ggplot2 es
la que veréis habitualmente, yo también hago mis gráficos así, solo que
para entender mejor el funcionamiento, la sintaxis de
ggplot2, os lo tengo que contar otra vez de una forma un
poco diferente o ampliada.
Un gráfico de ggplot2 se inicia llamando a la función
ggplot() eso es cierto y también es verdad que generalmente
dentro de ggplot() se indica el data.frame que vas a
utilizar y con aes() que variables vas a usar y con que
elementos visuales o estéticos quieres asociar cada una de la variables
que vas a utilizar4. Correcto, pero …. en realidad un gráfico
ggplot2 se hace por capas, cada capa se especifica con una función de la
familia geom_xx(), así que en realidad los datos y las
aes() se “deberían” especificar dentro de la función
geom_xx()`.
Parece un poco de lío pero en cuanto lo entiendas es muy fácil y te puede dar más flexibilidad a la hora de hacer tus gráficos. Empecemos: ¿recuerdas que hacen las lineas/expresiones de abajo?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_line()
Podemos pensar que las funciones que hacen la representación gráfica
realmente son las geom_xx(); es ahí donde deberíamos
especificar los datos y variables/estéticas que queremos usar, pero si
no las especificamos en la función geom(), entonces,
ggplot2 mirará a ver si existen, si están especificados, dentro de
ggplot().
Ahora que ya sabemos el funcionamiento básico de
ggplot2, veamos algunos detalles mediante algunos ejemplos.
Hasta ahora hemos especificado el data.frame que queremos graficar con
ggplot(data = my_df) o con ggplot(my_df) y las
variables que queremos ver, y a que propiedad estética queremos
asociarla, con la función aes() dentro de
ggplot(). Si lo hacemos así, todos los
geoms_xx() que utilicemos compartirán el conjunto de datos
y las variables/estéticas a mappear y mostrar; pero a veces, en gráficos
más complejos podemos querer hacer que cada geom_xx()
muestre datos y/o variables distintas.
Entender que cada geom_xx() puede estar asociado a
distintos data.frames y/o variables es importante para tener más
versatilidad con ggplot2.Por ejemplo, las siguientes tres
expresiones hacen el mismo gráfico. Se suele utilizar la primera
expresión, pero la segunda y tercera expresiones son “más flexibles”,
aunque es verdad que si sólo se utiliza un geom_xx() no
ganamos nada por usar la segunda o tercera expresión, pero no será el
caso si en nuestro gráfico necesitamos usar varios
geom_xx()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length))
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length))
Fíjate, como detalle, pero importante, que si utilizas la tercera
expresión; es decir, si especificas los datos dentro de la función
geom_xx(), es necesario poner el nombre del argumento ; es
decir, debes poner data = iris, no puedes poner solo
iris. Yo me olvido siempre de este detalle5.
En este caso (como el gráfico solo tiene una capa, como sólo usamos
un geom(_xx)) no ganamos nada por usar la segunda o tercera
expresión; PERO, cuando usemos varios geom_xx() esto nos
dará muchas posibilidades para nuestro gráfico.
Intenta descubrir las diferencias y funcionamiento de las 3 siguientes instrucciones. Recuerda que puedes correr las instrucciones en R para ver que hacen exactamente.
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
Veámoslas una a una:
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
En este caso los 2 geoms comparten el conjunto de datos (iris) y las variables/estéticas a graficar
geom_point()ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth()
geom_smooth()ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
Espero, seguro!!, que te has dado cuenta de que si especificas el
data.frame y las variables/estéticas dentro de ggplot()
esto afectará a todos los geoms del gráfico; pero lo que se especifique
dentro de un geom_xx() solo afecta a esa geometría.
Otro ejemplo para entenderlo, ¿por qué no funciona la siguiente expresión?
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length)) + geom_smooth(aes(color = Species))
Pues porque para poder representar la linea suavizada se utiliza
geom_smooth(), y geom_smooth() necesita como
mínimo tener variables asociadas a las estéticas x e y. Como veis,
dentro de geom_smooth() solo hemos especificado la estética
“color” y tampoco hemos especificado en la función ggplot()
que variables se asocian con x e y. Por lo tanto,
geom_smooth() no puede hacer su trabajo, le faltan los
“datos” de x e y para calcular/obtener la linea suavizada.
Vamos con otros ejemplos. La siguientes expresiones tampoco funcionarán6 si intentáis correrlas en vuestro ordenador. ¿Por qué?
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length)) + geom_line(aes(Sepal.Length, Petal.Length))
ggplot(aes(Sepal.Length, Petal.Length)) + geom_point(data = iris) + geom_line()
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length)) + geom_line()
Otro ejemplo: hagamos algo más marciano/complicado. Supón que quieres hacer un gráfico diferenciando los puntos por color para las tres especies de lirios, pero quieres que solo se vea la linea suavizada para las dos especies más grandes (virginica y versicolor). Los lirios más pequeños son los de la clase setosa. Igual se puede hacer de otra forma pero la que me viene a la cabeza es hacer lo siguiente:
Primero, crear un dataset que sólo contenga a los lirios grandes, los de las especies virginica y versicolor.
iris2 <- iris %>% filter(Species != "setosa") #- me quedo con los lirios que no son de clase "setosa"
Para después hacer el gráfico con cualquiera de las 2 expresiones siguientes. Prefiero la segunda porque hay que teclear/escribir menos, pero puede que sea más didáctica la primera.
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_smooth(data = iris2, aes(Sepal.Length, Petal.Length) )
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth(data = iris2)
Otro ejemplo más: ¿y si quisiéramos que las 2
especies grandes se representen con el mismo color? Hay varias
soluciones, una de las más marcianas es la que propongo abajo. Es una
solución rara, pero creo que os ayudará a entender
ggplot2
Primero voy a crear un nuevo data.frame sólo con las observaciones de los lirios pequeños, los de la clase setosa.
iris_setosa <- iris %>% filter(Species == "setosa") #- me quedo con los lirios pequeños, los de clase "setosa"
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_point(data = iris_setosa, aes(color = Species)) + geom_smooth(data = iris2,aes(Sepal.Length, Petal.Length) )
Otra solución, quizás más lógica, consiste en primero agrupar las 2 especies de lirios grandes (versicolor y virginica) en una sola clase.
iris_solo_2_clases <- iris %>% mutate(Species_2 = ifelse(Species %in% c("versicolor", "virginica"), "versi_virgi", "setosa"))
Para después hacer el gráfico. Además el gráfico lo podemos hacer al menos de 2 maneras, la segunda mucho mejor, la primera expresión es un poco enrevesada:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_point(data = iris_setosa, aes(color = Species)) + geom_smooth(data = iris_solo_2_clases,aes(Sepal.Length, Petal.Length, color = Species_2) )
ggplot(iris_solo_2_clases, aes(Sepal.Length, Petal.Length, color = Species_2)) + geom_point() + geom_smooth()
Como veis, en ggplot2 hay varias maneras de hacer el
mismo gráfico. Esto al principio puede abrumar/molestar, pero muestra la
flexibilidad de la sintaxis.
Para ir acabando con la “filosofía”/sintaxis/gramática de
ggplot2 intenta imaginar que gráficos hacen las 6
expresiones de más abajo.
Si no puedes, recuerda que siempre puedes ejecutar las ordenes en el ordenador. Fíjate sobre todo en la tercera expresión
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point(color = "purple") + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth(color = "brown")
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length, color = Species) ) + geom_smooth(aes(Sepal.Length, Petal.Length, color = Species))
En la tercera expresión se especifica color = Species
dentro de aes() en ggplot(), así que, de
momento, todos los geoms del gráfico deberían diferenciar por especies
de lirios usando el color, PERO, después se vuelve a usar el argumento
color dentro de geom_point(), pero fíjate que
no va dentro de de aes(), va fuera. Concretamente hacemos
lo siguiente: geom_point(color = "purple"); es decir, para
la capa de puntos, y solo para la capa de puntos que se crea con
geom_point(), estamos asociando la estética color, no a una
variable, sino a un color fijo. Sin embargo, para la otra capa del
gráfico, la que resulta de usar geom_smooth() sigue siendo
valido que la estética color está asociada a la variable Species.
Un detalle: imagina que en un gráfico en el que has fijado 3
estéticas dentro de ggplot(aes()). En principio las 3
estéticas afectarán a todos los geom_xx() que utilices en
tu gráfico, pero si quisieras que, por ejemplo, la estética color no
afectase a un geom concreto, podrías hacer lo siguiente:
geom_xx(aes(color = NULL)).
Como puedes imaginar, aún tenemos que ver más elementos de
ggplot2. Como mínimo los títulos y leyendas, los ejes, el
tema, coordenadas, etc… vamos a ello!!
Ya hemos presentado los principales elementos de los gráficos hechos
con ggplot2, los que tienen que ver con la representación
de las variables. Pero es evidente que un gráfico tiene muchos más
elementos, y lógicamente hay que conocerlos un poco para poder ajustar
los gráficos a nuestras necesidades y mejorar la calidad de nuestros
gráficos.
Ejemplos de otros elementos son: títulos del gráfico y de los ejes, “theme” del gráfico, small multiples o faceting, anotaciones etc…
En está sección iremos más rápido. Se presentarán solamente algunos
ejemplos, conceptos y/o aclaraciones. Si necesitas profundizar más en
estos elementos, puedes acudir a la referencia
oficial de ggplot2 o al bookdown de ggplot2.
Ya dijimos que los gráficos ggplot se componen de capas o layers. Para nosotros, hasta ahora, una capa estaba compuesta de 3 elementos:
un conjunto de datos
un conjunto de variables mapeadas con aes() a
propiedades estéticas
una geometría, con geom_xx()
Es evidente que en todos los geoms no se pueden especificar todas las
características estéticas. Por ejemplo si usas geom_point
no podrás especificar la anchura o el tipo de las lineas, porque no
estás usando lineas sino puntos. Para ver que estéticas admite cada geom
tendrás que mirar la ayuda de cada geom. Al final de este
post tienen un gráfico interactivo con el que se puede ver
fácilmente que características estéticas admite cada geom. Por ejemplo
geom_bar(), que sirve para hacer gráficos de barras, no
admite mappear variables al eje Y, ya que en el eje Y se
visualizan/mapean las frecuencias absolutas o relativas de la variable
que se representa en el eje X.
Esto es lo básico que hay que saber, pero en realidad, una capa
necesita de dos elementos más: una stat (o
transformación estadística) y una posición. Estos dos
últimos elementos son necesarios pero la verdad es que podríamos seguir
haciendo gráficos con ggplot2 sin conocerlos. ¿Por qué?
Pues porque si en una capa no los especificamos, lo hace
ggplot2 por nosotros. Lo ha estado haciendo hasta ahora en
todos los gráficos que llevamos hechos. Pero claro, saber como utilizar
estos elementos nos dará más flexibilidad a la hora de hacer
ggplots.
Generalmente las capas se van añadiendo con la familia de funciones
geom_xx(), PERO también se pueden añadir
capas con otra familia de funciones stat_xx().
Aparte de estos cinco elementos (datos, aes(), geom, stat y posición) los gráficos ggplot pueden tener más elementos. Veámoslos uno a uno.
Es evidente que un gráfico para ser efectivo y mostrar su mensaje con
claridad debe tener un título y/o subtítulo ilustrativo y debe mostrar
información relevante sobre que variables se grafican los ejes X e Y.
Este tipo de elementos pueden modificarse de varias maneras, pero nos
centraremos en la función labs().
Fíjate que con la función labs(), de labels, podemos
cambiar los títulos del gráfico, de los ejes y también de las
leyendas.
En los títulos (tanto del gráfico, como de los ejes y leyendas)
también se pueden cambiar otras características; por ejemplo, cambiar el
tamaño, la fuente o el color, pero eso será tarea de otra función de
ggplot2: del grupo de funciones theme_(). Pero
el tema o theme de los gráficos lo veremos en el siguiente apartado.
Tomemos el siguiente gráfico como referencia y sobre él iremos añadiendo elementos:
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point()
p
Con la función labs() podemos añadirle un título,
subtitulo, pie de gráfico o caption. También podemos cambiar el
título de los ejes X e Y, así como también el titulo de la leyenda para
color, o para otras estéticas que utilicemos en el
gráfico.
Es suficiente con ver un ejemplo:
p + labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo",
subtitle = "(diferenciando por especie de lirio)",
caption = "Datos provenientes del Iris dataset",
x = "Longitud del sépalo",
y = "Longitud del pétalo",
color = "Especie de lirio")
Si quisieras eliminar completamente los títulos del
eje X podrías hacerlo en el anterior chunk fijando x = NULL
dentro de la función labs().
En lugar de usar la función labs(), también podemos
utilizar las funciones auxiliares xlab() e
ylab()
p + labs(color = NULL, x = NULL) #- borra el título de la leyenda y del eje X
p + xlab(NULL) + ylab(NULL) #- elimina títulos de los ejes X e Y
Themes control the display of all non-data elements of the plot. You can override all settings with a complete theme like theme_bw(), or choose to tweak individual settings by using theme() and the element_ functions. Use theme_set() to modify the active theme, affecting all future plots.
Para cambiar detalles de la apariencia del gráfico como el tamaño,
fuentes y color de los títulos, pero también de los puntos, las lineas,
el fondo del gráfico, la apariencia de las grid-lines, el lugar para las
leyendas, etc… etc… contamos con las “funciones de tema”; todas ellas
comienzan con theme_()
En general con las funciones theme_() podemos
cambiar/ajustar cualquier elemento del gráfico, con la excepción de la
propia representación de los datos (ya sabemos que esto se hacen con las
funciones geom_()). Estos elementos afectan a la apariencia
y detalles del gráfico, pero no a la relación entre variables que se
muestra realmente en el gráfico.
Para empezar a entender que hacen las funciones relacionadas con el
theme, señalar que ggplot2 incorpora un conjunto de “temas”
que podemos utilizar para cambiar la apariencia del gráfico a nuestro
gusto. Puedes verlos todos aquí. El
tema que usa por defecto ggplot2 es
theme_gray(). Veamos a los themes en acción:
p + theme_gray() #- tema por defecto
p + theme_light()
p + theme_dark()
p + theme_classic()
p + theme_minimal()
p + theme_void()
El paquete de R ggthemes incorpora una amplia lista de temas adicionales, algunos de ellos tratan de replicar el estilo de corporaciones famosas como The Economist o Stata. En el tutorial no se ven bien los gráficos porque los he hecho pequeñitos, pero prueba a hacerlos tú mismo y verás que son good-looking. Veamos algunos:
library(ggthemes)
p + theme_economist()
p + theme_fivethirtyeight()
p + theme_stata()
p + theme_solarized()
También podemos definir un tema propio para que el gráfico se ajuste los más posible a nuestras preferencias.
# define custom theme
my_theme <- theme(axis.text.x =
element_text(colour = "grey20", size = 12, angle = 90, hjust = 0.5, vjust = 0.5) , axis.text.y = element_text(colour = "grey20", size = 12) ,
text = element_text(size = 16))
p + my_theme
Se puede fijar el tema/theme de los gráficos con la función
theme_set(). Por ejemplo:
theme_set(theme_minimal()) #- un tema concreto
theme_set(theme_minimal() +
theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())) #- un tema modificando algunas opciones, que ele eje x no muestre ticks ni escalas
Si quieres volver al theme por defecto:
theme_set(theme_gray())
Ejemplos de algunos elementos cuya apariencia que se pueden cambiar
con theme()
p + theme(legend.position = "none") #- que no aparezca leyenda
p + theme(legend.position = "bottom") #- leyenda abajo
p + theme(legend.direction = "horizontal") #- leyenda horizontal!!
p + theme(legend.title = element_text(size = 22)) #- título de la leyenda a 22
p + theme(legend.key.size = unit(2.4, "cm")) #- tamaño de los cuadros de la leyenda
p + theme(text = element_text(size = 20, face = "bold")) #- cambiar el tamaño de todos los elementos de texto
p + theme(text = element_text(face = "bold")) #- pone en negrita todos los elementos de texto
p + theme(axis.text.x = element_text(colour = "pink", size = 12, angle = 90, hjust = 0.5, vjust = 0.5)) # apariencia de la escala del eje x
p + theme(axis.title.y = element_text(size=25, angle = 45)) #- tamaño y angulo del texto del eje Y
p + theme(plot.subtitle = element_text(hjust = 3)) #- posición horizontal del subtitulo (si lo tuviese)
p + theme(plot.caption = element_text(hjust = 3)) #- posición vertical del pie de gráfico (si lo tuviese)
p + theme(panel.background = element_rect(fill = "green", colour = "pink", linetype = "longdash", size = 3.5))
p + theme(panel.background = element_blank())
p + theme(panel.background = NULL)
p + theme(plot.background = element_rect(fill = "pink", colour = "purple", linetype = "dotted", size = 7))
Si quieres ver todos las características que controla y que por tanto
puedes modificar con theme(), usa la ayuda de la función
theme() o ejecuta en R args(theme). Aunque
casi mejor verlas en esta
infografía de Henry Wang o en este
post de Isabella Benabaye con las opciones que suele cambiar
ella.
En general, si quieres cambiar algún elemento de un ggplot, has de
hacer theme(elemento = element_text()). Si quieres eliminar
por completo algún elemento del gráfico, por ejemplo las grid-lines del
gráfico, harías theme(panel.grid = element_blank()).
Evidentemente todo esto es imposible de aprender, sólo tienes que saber que cualquier elemento del gráfico se puede cambiar y tienes que saber buscar e interpretar la ayuda.
Se poco de colores, pero claro si quieres cambiar la apariencia de los gráficos, has de saber los colores de R, así que:
Aquí
tienes una guía para elegir color. Si solo quieres ver la lista de
nombres de los colores en R ejecuta:
aa <- as.data.frame(colours())
Si sabes el nombre del color que quieres, aquí, podrás buscarlo y ver su color y su codificación en RGB y Hex.
También es interesante el paquete paleteer que agrupa un conjunto amplio de paletas de colores para usar en R.
Por último, no sé si conocéis el webcomic XKCD. Pues en R también hay un paquete y un theme para hacer gráficos al estilo XKCD. Es el paquete xkcd cuyo autor es Emilio Torres-Manzanera de la Universidad de Oviedo. Aquí podéis ver algunos gráficos hechos con este estilo en R.
Intenté hacer un gráfico con su theme, pero desafortunadamente no me salió; pero justo al día siguiente vi este tweet7 que hace algo parecido con datos de los Simpsons y su código sí me ha funcionado, además simula/construye el estilo XKCD desde cero.
Además, después vi que Evangelyne Reinolds hizo esta maravilla. Lo haremos en clase?! En este post puedes encontrar el código para reproducir una de las historias o viñetas de XKCD.
El sistema gráfico de ggplot2 incorpora una técnica
especial llamada “faceting” que permite dividir un gráfico en múltiples
gráficos. Cada uno de esos múltiples gráficos se realiza sólo para las
observaciones de una de los valores de una variable categórica (o
factor) incluido en el conjunto de datos. Es más fácil hacerlo que
explicarlo/escribirlo.
Por ejemplo, en iris tenemos la variable
Species, que es categórica. Lo que se hace con el
“facetting” es dividir el dataset en grupos y hacer el mismo gráfico
para cada uno de los grupos. Los grupos se van a definir en función de
los valores de la variable Species. Recuerda que hay tres tipos o
especies de lirios.
Para hacer un “facetting graph” podemos usar las funciones
facet_wrap() y facet_grid().
Por ejemplo, con la función facet_grid() puedes elegir
entre hacer los small multiples por filas o por columnas. Empecemos
haciendo un facetting por columnas. Además, con
facet_grid() se pueden usar varias sintaxis, pero la que
aparece en la cheatsheet actual
de ggplot2 y, por tanto, la recomendada es las que ves en la segunda
linea:
#p + facet_grid( . ~ Species) # old sintaxis
p + facet_grid(cols = vars(Species)) # gráficos x columnas, separando por valores de 'Species'
Ahora por filas:
p + facet_grid(rows = vars(Species)) # gráficos x filas