Gráficas con ggplot
Manual breve de cómo hacer gráficos con la librería ggplot2
, que es el más usado y completo paquete gráfico de R, con la ventaja de usar los criterios de gramática gráfica en su estructura.
La gramática gráfica es un sistema de representación ordenado del trazado de gráficos. Consiste en dividir las partes que intervienen en pintar datos y analizarlo como si de la gramática ortográfica se tratase, otorgando a cada elemento una función característica. Los objetos así generados se definen por capas superpuestas de características.
La ventaja de esto es que trata a los gráficos como objetos. Cuando pintamos con plot
lo que hacemos es un dibujo, al que añadimos capas de pinturas nuevas, pero en ggplot
la idea es diferente, pues creamos un objeto al que añadimos o quitamos propiedades-capas por lo que al pintarlo siempre tenemos la realidad del objeto y no la última capa de la pintura como ocurre cuando usamos plot
.
La librería ggplot2
que contiene la función gráfica ggplot
, forma parte del entorno tidyverse
, esto muy importante pues nos indica una relación directa entre el manejo, orden y limpieza de los datos con su representación. Es fundamental que antes de pintar los datos ordenemos la tabla origen de acuerdo a nuestros intereses gráficos y para ello las funciones de tidyverse
y las de agrupamiento o sección de los datos son tan importantes como las mismas funciones gráficas de representación. Un buen trabajo previo sobre los datos, facilita la representación de estos.
Para cargar ggplot
podemos hacerlo:
# Instalando tidyverse
install.packages("tidyverse")
library(tidyverse) # lo que carga por defecto ggplot2
# Alternativamente, podemos instalar solo ggplot2:
install.packages("ggplot2")
library(ggplot2)
Gramática gráfica
La gramática gráfica que usa ggplot
consiste en ordenar y crear objetos gráficos con una estructura de ensamblado predefinida. Según las definiciones creadas por Leland Wilkinson en 1999 los gráficos son objetos creados por supreposición de capas. Estas capas son principalmente:
data:
los datos que se desean pintaraesthetics:
esta capa indica las variables que pintamos.geometries:
los elementos visuales usados para representar los datos.facet:
multigráficas pequeñas.statistics:
representación agregada de los datos.coordinates:
el espacio en el que se pintan los datos.themes:
el formato de la tinta o lienzo.
ggpplot incorpora la gramática gráfica de capas por lo que cualquiera gráfica se complone de capas superpuestas de estas 7 caracteristicas principales que hemos visto.
Los datos de origen es la más básica, pero la capa aesthetics
es la más compleja, pues nos permite una amplia variedad en los gráficos. En particular, con este elemento podemos incluir variables nuevas en la gráfica que se suman a las dos de ordenadas y abcisas. Con aesthetics
podemos representar 7 características gráficas: x, y, color, fill, size, alpha, labels y shape que varien en función de los datos.
Para usar algunas de estas carcterísticas, las variables deben ser factores, o convertidas a factor, pues por ejemplo las formas con shape
no son infinitas y solo admite un número pequeño de variaciones.
La capa de geometrias es la que define lo que conocemos como tipo de gráfico, de barras, de área, histograma. el resto de capas los vemos más como complementos de formato en la representación.
Aspecto del gráfico
Una gráfica con el paquete ggplot2 se hace usando la función ggplot()
e incorporando capas de los 7 parámetros de la gramática vistos, datos con data
, aesthetics
con aes()
, geometrías con geom_
. Además se añaden otras multiples funciones con solo usar +
para las etiquetas, títulos, leyendas y aspecto general del gráfico.
Estas son las principales funciones de personalización:
- Título:
labs(title = "titulo gráfico")
labs(subtitle = "subtitulo")
labs(x = "eje x", y = "eje ordenadas")
labs(y = expression('texto eje Y m'^3))
- Leyenda:
theme(legend.position="bottom")
theme(legend.text = element_text(colour="blue", size=6))
- escalas:
scale_color_manual(values=c("navy", "red2"))
- temas:
theme_minimal()
theme_bw()
-limites ejes:
xlim(0,150) + ylim(5,15)
define los límites de los ejes
- escalas x-y log
scale_x_log10()
convierte la escala eje x en logarítmicascale_y_log10()
scale_y_log10()
breaks = trans_breaks("log10", function(x) 10^x),
labels = trans_format("log10", math_format(10^.x)))
scale_x_continuous(breaks=pretty(dtnilo$ano, n = 10), name="año")
Vamos a empezar con el ejemplo más simple:
Gráficos de 1 variable
Son gráficos que representan los valores de una sola variable de forma resumida o agregada, los más habituales son los histogramas que suman el número de apariciones de un valor y lo representan gráficamente. También los gráficos boxplot.
Cuando solo hay una variable en aes()
especificamos solo la que vamos a representar.
Vamos a usar los datos de ejemplo de la base de datos diamonds
que indica diferentes características de diamantes reales medidos.
Histogramas
Los histogramas son gráficas de frecuencia, se hacen con geom_histogram()
, como parámetros podemos pasar el numero de bandas o barras bins= 6
o el ancho de cada barra en valores de la variable binwidth=0.5
.
Aunque sean gráficas de una variable, podemos usar otra de las variable como parámetro de color o tamaño para distinguir los resultados. Esta nueva variable deben ser factores según el caso.Ejemplo:
require(ggplot2)
str(diamonds)
## tibble [53,940 x 10] (S3: tbl_df/tbl/data.frame)
## $ carat : num [1:53940] 0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
## $ cut : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
## $ color : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
## $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
## $ depth : num [1:53940] 61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
## $ table : num [1:53940] 55 61 65 58 58 57 57 55 61 61 ...
## $ price : int [1:53940] 326 326 327 334 335 336 336 337 337 338 ...
## $ x : num [1:53940] 3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
## $ y : num [1:53940] 3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
## $ z : num [1:53940] 2.43 2.31 2.31 2.63 2.75 2.48 2.47 2.53 2.49 2.39 ...
# graficos de una variable con geom_histogram
ggplot(diamonds, aes(carat)) +
labs(title='Histograma caras de diamantes')+
geom_histogram(fill="blue")
# agrupamos los valores de carat en anchos de banda de 0.5
ggplot(diamonds, aes(carat)) +
geom_histogram(binwidth = 0.5)
# distinguimos por el corte como color usando aes para otra variable
ggplot(diamonds, aes(carat,fill = cut)) +
geom_histogram(bins = 10)+
labs(title='Frecuencias de caras de diamantes según corte') +
geom_text(aes(x=3,y = 20000, label="en 3, 20000, pintamos hola"),color = "blue")
Veamos otro ejemplo con la serie temporal de caudales del río Nilo. Introducimos geom_rug()
para marcar cada ocurrencia real en el eje x.
# datos de ejemplo de la dataset Nile
# los transformamos en un dataframe
dtnilo<-data.frame(caudal=as.matrix(Nile), ano=time(Nile))
maximo<-c(dtnilo$ano[which.max(dtnilo$caudal)],max(dtnilo$caudal))
# vemos los datos como linea
ggplot(data = dtnilo, aes(x=ano, y=caudal))+
geom_line(color = "#00AFBB", size = 2)+
labs(title='Serie de caudales maximos del Nilo')+
labs(x = 'Año', y = expression('Caudal en m'^3))+
geom_point(aes(x=maximo[1],y=maximo[2]))+
geom_text(aes(x=maximo[1],y=maximo[2], label=maximo[2]),nudge_x = 2, color="blue")
# vemos un histograma de frecuencias
ggplot(dtnilo, aes(caudal))+
geom_histogram(bins=10, fill="bisque4", color="black")+
labs(title='Frecuencia de caudales máximos del Nilo')+
geom_rug()
Los histogramas pueden complicarse con ggplot:
library(ggplot2)
set.seed(5556)
df<-data.frame(x=runif(500),y=rnorm(500,12))
# pintamos histograma de y con opciones gráficas
ggplot(df, aes(y)) +
geom_histogram(aes(fill=..count..)) +
scale_fill_gradient("Count", low = "green", high = "red")+
geom_density(position = "stack")
# funcion de densidad
ggplot(df, aes(x=y)) +
geom_histogram(aes(y =..density.., fill=..count..)) +
geom_density(lwd=2,adjust = 1/2)
grafico de frecuencia
Otra posibilidad equivalente al histograma es el gráfico de frecuencias con geom_freqpoly()
ggplot(diamonds, aes(price, colour = cut)) +
geom_freqpoly(binwidth = 500, size=2)
ggplot(df, aes(x=y)) +
geom_freqpoly(size=2)
grafico q-q
Este gráfico representa la desviación respecto a la normal de los datos de una variable.
library(tidyverse)
# hacemos una data frae con valores aleatorios de 3 funciones
df <- data.frame(normal = rnorm(100),tsudent=rt(100, df = 5),uniforme=runif(100))
# juntamos en una sola variable las 3 variables
df1<- df %>% gather("normal","tsudent","uniforme",key="tipo",value="valor")
# pintamos qqplot por variable
ggplot(df1, aes(sample = valor, colour = factor(tipo))) +
stat_qq() +
stat_qq_line()
Dos variables
Barras
Las barras muestran 2 o tres variables ya que podemos incluir el color como otro eje de diferenciación de los valores por grupos.
# frecuencias según % de corte
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill=cut))
# añadimos otra variable como color
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity,alpha = 0.6))
# para comparar entre grupos podemos hacer
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill")
boxplot
Aunque son de una variable, son útiles para comprar dos variables también al representar los rangos de cada grupo:
# grafico boxplot
ggplot(data = mpg, mapping = aes(x = class, y = hwy, fill=class)) +
geom_boxplot()
Puntos X-Y
Los gráficos de puntos se hacen con geom_point()
. Usaremos de muestra los datos de la tabla mpg
que se aportan con ggplot.
Hay muchas opciones de personalización en las gráficas de puntos, la más habitual es usar otra variable (que sea factor) para representar los datos en 3 dimensiones. Es decir, usar además de x-y, otra variable como dimensión y representarla cambiando el color o el tamaño del punto.
Veamos un ejemplo completo:
# vemos las variables de mpg
str(mpg)
## tibble [234 x 11] (S3: tbl_df/tbl/data.frame)
## $ manufacturer: chr [1:234] "audi" "audi" "audi" "audi" ...
## $ model : chr [1:234] "a4" "a4" "a4" "a4" ...
## $ displ : num [1:234] 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
## $ year : int [1:234] 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
## $ cyl : int [1:234] 4 4 4 4 6 6 6 4 4 4 ...
## $ trans : chr [1:234] "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ...
## $ drv : chr [1:234] "f" "f" "f" "f" ...
## $ cty : int [1:234] 18 21 20 21 16 18 18 18 16 20 ...
## $ hwy : int [1:234] 29 29 31 30 26 26 27 26 25 28 ...
## $ fl : chr [1:234] "p" "p" "p" "p" ...
## $ class : chr [1:234] "compact" "compact" "compact" "compact" ...
# pintamos una grafica de puntos de 4 variables x-y size y color
ggplot(data = mpg) +
labs(title = "Coches")+
geom_point(mapping = aes(x = displ, y = hwy, size = class, color=manufacturer))
# usamos shape como diferencia
ggplot(data = mpg) +
labs(title = "Coches")+
geom_point(mapping = aes(x = displ, y = hwy, shape = class), color="blue")
Los símbolos de puntos pueden ser los siguientes:
Hay que tener en cuenta que si queremos un color determinado no lo podemos meter dentro de aes()
sino fuera, como en el ejemplo anterior.
jitter
En muchas ocasiones al pintar gráficos x-y, existen superposición de muchos valores en el mismo punto , algo que no puede apreciarse en los gráficos. También dan la sensación de ser gráficos en malla o grid, como el caso anterior. Para evitar esto hay un tipo especial de gráfico x-y que es el jitter que introduce cierta aleatoriedad de forma que evita superposiciones de los puntos próximos y se puede ver donde está la mayor concentración.
# diferencia entre jitter y sin esto
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point( alpha=0.6, size=2)+
labs(title = "Sin jitter")
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_jitter(alpha=0.6, size=2)+
labs(title = "uso de jitter para evitar grafico con grid")
Líneas - Áreas
Los gráficos de lineas se hacen con geom_line()
y los de áreas con geom_area()
.
Usamos los datos del Nilo del primer ejemplo para una gráfica compleja.
Como verás hacemos primero una transformación de los datos, para tener una tabla limpia con las variables que queremos representar. Nos inventamos dos puntos de aforo con los que hacemos la tabla original, que después juntamos con gather
para tener una tabla con los valores deseados.
require(tidyverse)
# nuevo punto de aforo
dtnilo$caudal2<-dtnilo$caudal-400
# lipiamos la tabla y unimos en mismas columnas los datos de las 2 variables
dtnilo2<- dtnilo %>% gather("caudal","caudal2",key="aforo",value="valor",-ano)
# convertimos en factor la variable aforo
dtnilo2$aforo<-as.factor(dtnilo2$aforo)
str(dtnilo2)
## 'data.frame': 200 obs. of 3 variables:
## $ ano : Time-Series from 1871 to 1970: 1871 1872 1873 1874 1875 ...
## $ aforo: Factor w/ 2 levels "caudal","caudal2": 1 1 1 1 1 1 1 1 1 1 ...
## $ valor: num 1120 1160 963 1210 1160 1160 813 1230 1370 1140 ...
# Pintamos la gráfica como linea distinguiendo según aforo
ggplot(data = dtnilo2, aes(x=ano, y=valor, group=aforo))+
geom_line(aes(linetype=aforo, color=aforo))+
geom_point(aes(shape=aforo, color=aforo))+
labs(title='Serie de caudales máximos del Nilo en dos aforos')+
labs(x = 'Año', y = expression('Caudal en m'^3))+
scale_color_manual(values=c("navy", "red2"))+
theme(legend.position="bottom")
# de forma similar un gráfico de área
# cambiando la opcion position=stack apila una encima de otra
ggplot(data = dtnilo2, aes(x=ano, y=valor, fill=aforo))+
#geom_area(color="black", alpha=0.6,position='stack')+
geom_area(color="black", alpha=0.6,position='identity')+
labs(title='Serie de caudales máximos del Nilo en dos aforos')+
labs(x = 'Año', y = expression('Caudal en m'^3))+
scale_color_manual(values=c("navy", "red2"))+
theme(legend.position="right")
Se puede incluso cambiar el grosor de la gráfica según un valor:
# Cambio de grosor de linea
ggplot(data=economics, aes(x=date, y=pop, size=unemploy/pop))+
geom_line()+
geom_point()
Paneles - facets
Las funciones facet_wrap()
y facet_grid()
nos permiten dibujar multigráficas de los datos fácilmente.
# Gráfica de paneles
ggplot(dtnilo2,aes(x=ano, y=valor, color=aforo))+
# facet_wrap ocupa todo y facet_grid hace una tabla x-y de paneles
# facet_grid(VARZ~VART,margins=TRUE)
facet_wrap(~ aforo )+
geom_line()
# Gráfica de paneles
iris<-datasets::iris
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_jitter(alpha = 0.6)+
facet_grid(. ~ Species)
Añadir estadísticos
Con ggplot
es muy fácil añadr un modelo de ajuste a los datos, existen funciones para pintar y calcularlos como stat_smooth()
. Los argumentos principales son el modelo (lm= linear model), y si pinta o no las lineas o banda de probabilidad con se=TRUE o FALSE.
ggplot(mammals, aes(x = body, y = brain)) +
geom_point(alpha = 0.6) +
coord_fixed() +
scale_x_log10() +
scale_y_log10() +
stat_smooth(method = "lm",
col = "#C42126",
se = FALSE, size = 1)
Por ejemplo vamos a añadir una linea de regreseión a los datos de caudales del Nilo y las bandas de certeza.
# leyenda del gráfico
ggplot(dtnilo,aes(x=ano, y=caudal))+
labs(title = 'Evolución de caudales del Nilo')+
geom_line(color="red")+ geom_point()+
theme(legend.position="top", legend.text = element_text(colour="blue", size=6)) +
# añade regresion lineal a cada conjunto de datos
geom_smooth(size = 1, linetype = 1, method = "lm", se = TRUE)+
theme_bw()
Cambio de ejes
Podemos intercambiar los ejes a e y añadiendo la función coord_flip()
.
Themes
Los temas son formatos predefinidos de las gráficas de ggplot. Podemos personalizarlo todo, pero hay muchos modelos ya hechos según el uso final de nuestra gráficas. Los themas incluidos por defecto son: theme_bw()
,theme_linedraw()
,theme_light()
,theme_minimal()
,theme_classic()
, theme_void()
, theme_dark()
.
Aparte si instalamos la librería ggthemes
tendremos muchos más como :
theme_tufte()
,theme_hc()
,theme_calc()
,theme_wsj()
…
install.packages("ggthemes") # Install
library(ggthemes) # Load
Texto y tipo de letra
Se puede añadir texto a los objetos gráficos con geom_text()
, hay muchas características del texto que se pueden definir, ver esta web para más detalles.
También el tamaño y fuente se pueden cambiar con: base_size:
y base_family:
, aunque necesitamos la librería extrafont
y cargar los tipos de letra de windows antes.
library(extrafont)
# hacer la primera vez:
#loadfonts(device = "win")
ggplot(dtnilo,aes(x=ano, y=caudal))+
labs(title = 'Evolución de caudales del Nilo')+
labs(subtitle = 'con fuente calibri')+
geom_line(color="red")+ geom_point()+
scale_x_continuous(breaks=pretty(dtnilo$ano, n = 10), name="año")+
theme(legend.position="top", legend.text = element_text(colour="blue", size=6)) +
geom_text(aes(label=caudal),hjust = 0, nudge_x = 0.05, color="blue",size=3)+
theme(text=element_text(size=12, family="Calibri"))+
theme_bw()
Chuleta
Hay una chuleta de ggplot muy buena que conviene tener a mano para representar cualquier gráfico. Está disponible aquí.