Graficas 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 según 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.
Quizás la definición de aesthetics
sea la más compleja y diferente, 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.
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.
Resumen
Empezamos por el final, pero es que siempre vienebien tener un resumen de algunas funciones de personalización de ggplot
válidas para todos los gráficos que creamos:
- 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")
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 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)
## Classes 'tbl_df', 'tbl' and 'data.frame': 53940 obs. of 10 variables:
## $ carat : num 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 61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
## $ table : num 55 61 65 58 58 57 57 55 61 61 ...
## $ price : int 326 326 327 334 335 336 336 337 337 338 ...
## $ x : num 3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
## $ y : num 3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
## $ z : num 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
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 una 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)
## Classes 'tbl_df', 'tbl' and 'data.frame': 234 obs. of 11 variables:
## $ manufacturer: chr "audi" "audi" "audi" "audi" ...
## $ model : chr "a4" "a4" "a4" "a4" ...
## $ displ : num 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
## $ year : int 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
## $ cyl : int 4 4 4 4 6 6 6 4 4 4 ...
## $ trans : chr "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ...
## $ drv : chr "f" "f" "f" "f" ...
## $ cty : int 18 21 20 21 16 18 18 18 16 20 ...
## $ hwy : int 29 29 31 30 26 26 27 26 25 28 ...
## $ fl : chr "p" "p" "p" "p" ...
## $ class : chr "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:

simbolos de puntos geom_point
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í.