ggplot2 es un sistema para crear gráficos de forma declarativa, basándose en una gramática para gráficos. Su mecánica es la siguiente: le proporcionamos los datos, le decimos cómo asignar variables a la estética, qué tipos de gráficas usar y él se encarga de los detalles. Permite crear gráficos complejos de manera sencilla, aunque también es cierto que puede resultar complejo para hacer gráficos sencillos.
Vamos a utilizar las librerías ggplot2
,
ggpubr
, readxl
y patchwork
(las
instalamos, caso de no haberlo hecho antes):
library(ggplot2)
library(ggpubr)
# Instala la librería readxl, caso de que no lo esté
if(!"readxl" %in% installed.packages())
install.packages("readxl")
# Carga la librería
library(readxl)
# Instala la librería patchwork, caso de que no lo esté
if(!"readxl" %in% installed.packages())
install.packages("patchwork")
# Carga la librería
library(patchwork)
Los diagramas de dispersión son útiles para representar dos variables numéricas (tanto discretas como continuas), habitualmente con el objetivo de determinar relaciones o patrones de comportamiento.
Si sólo nos interesa representar el diagrama de dispersión entre dos
variables numéricas, bastaría con usar la función de la librería base
plot
:
# Generamos n valores distribuidos uniformemente entre 0 y 10
n=100
v1=runif(n,0,10)
# Generamos los valores de y como una transformación lineal
# de los valores de x, más una componente aleatoria
v2=3*v1+2+rnorm(n,0,3)
# Regresentamos la nube de puntos
plot(v1,v2)
Para incluir la recta de regresión muestral, que modela su relación,
sería necesario estimarla con lm
y almacenar su resultado
en un objeto para poder representarlo en el gráfico:
# Estimamos la recta de regresión muestral y guardamos la salida
# en el objeto regresion, para poder utilizarla posteriormente
regresion<-lm(v2~v1)
# Representamos el conjunto de datos
plot(v1,v2,pch=21,col="red",bg="gray",cex=2/3,
main=" ", xlab="x", ylab="y",
family="Times New Roman" , font=2)
# Añadimos la recta de regresión muestral
abline(regresion)
# Añadimos la expresión de la recta de regresión muestral
text(1.5,30,paste("y = ",round(coef(regresion)[2],2),
"x +",round(coef(regresion)[1],2)))
Con ggplot2, la construcción del mismo gráfico es
más natural. Lo creamos con ggplot
pasándole como argumento
el nombre del conjunto de datos; dentro de la estética (función
aes()
) incluimos las variables x
e
y
; elegimos la geometría geom_point()
para la
nube de puntos y añadimos la recta de regresión muestral junto a su
banda de confianza con
geom_smooth
,(method="lm"
), su expresión con
stat_regline_equation()
(de la librería
ggpubr
) y también el valor del coeficiente de determinación
\(R^2\) con stat_cor()
,
situándolos en las posiciones introducidas en label.x
y
label.y
.
# Creamos un data.frame con las variables v1 y v2
data <- data.frame(x=v1,y=v2)
# Creamos el gráfico
ggplot(data)+
aes(x=x,y=y)+
geom_point()+
geom_smooth(formula=y~x, method="lm",se=TRUE,level=0.95)+
stat_regline_equation(label.x=7.5,label.y=15) +
stat_cor(label.x=0,label.y=30)
Además, se pueden usar muchas opciones para personalizar el gráfico
como alpha
para la transparencia, family
y
font
para el formato del texto, labs
para las
etiquetas del título, ejes, … A continuación vamos a tratar de imitar el
gráfico obtenido con plot
# Creamos un data.frame con las variables v1 y v2
data <- data.frame(x=v1,y=v2)
# Creamos el gráfico
ggplot(data)+
aes(x=x,y=y)+
geom_point(color="red",fill="grey",shape=21)+
geom_smooth(formula=y~x, method="lm",se=TRUE,level=0.95,color="black")+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman",font=2)+
stat_regline_equation(label.x=7.5,label.y=15) +
stat_cor(label.x=0,label.y=30)+
theme_classic()
En ocasiones puede interesarnos incorporar otras variables tanto cualitativas como cuantitativas para apreciar relaciones más complejas. Podemos hacerlo utilizándolas para identificar distintos colores o formas (si se trata de factores o variables cualitativas) o tamaño de los puntos (en el caso de que sean numéricas).
Generamos un nuevo conjunto de datos, algo más complejo, con una
variable cualitativa con 6 categorías (factor
), dos
variables cuantitativas continuas (x
e y
),
entre las que habrá distintas relaciones según el valor del factor, y
una variable cuantitativa discreta (z
).
#Indicamos el número de datos que deseamos generar.
n <- 120
#A continuación, vamos a generar distintas variables numéricas (continuas, discretas), así como variables categóricas.
v1 <- rep(c("A","B","C","D","E","F"),rep(n/6,6))
v2 <- runif(n,0,10)
v3 <- c(rep(5,20),v2[21:40],-v2[41:60]+10,
v2[61:80]^2/10,exp(v2[81:100])*10/exp(10),rep(7,20))+rnorm(n)
v4 <- trunc(v2^2)
#Para poder emplear la librería ggplot2 es necesario considerar el conjunto de datos como un data.frame
data <- data.frame(factor=v1,x=v2,y=v3,z=v4)
Si simplemente representamos las variables numéricas con un diagrama de puntos, no apreciamos ningún patrón de comportamiento:
ggplot(data)+
geom_point(aes(x=x,y=y))
Sin embargo, si separamos en distintos gráficos según los valores del
factor, con la función facet_wrap()
, podemos
distinguirlos:
ggplot(data)+
geom_point(aes(x=x,y=y,color=factor))+
facet_wrap(vars(factor))
También es posible agregar todos los datos en cada panel y destacar
los correspondientes para cada uno de ellos, creando una capa con los
mismos datos pero eliminando la variable categórica (en el ejemplo
factor
).
ggplot(data,aes(x=x,y=y,color=factor))+
geom_point(data=transform(data,factor=NULL),color="grey85")+
geom_point()+
facet_wrap(vars(factor))
Otra opción sería representarlos en un único gráfico, diferenciando las distintas categorías, por ejemplo por colores:
ggplot(data)+
geom_point(aes(x=x,y=y,colour=factor))
En este caso no es muy adecuada, pero sí lo sería cuando hay alguna relación entre los distintos patrones de comportamiento. Por ejemplo, lo que ocurre con este otro conjunto de datos:
#Indicamos el número de datos que deseamos generar.
n <- 120
#A continuación, vamos a generar distintas variables numéricas (continuas, discretas), así como variables categóricas.
v1 <- rep(c("A","B","C","D","E","F"),rep(n/6,6))
v2 <- runif(n,0,10)
v3 <- c(rep(0,20),1/4*v2[21:40],2+1/2*v2[41:60]+1,
v2[61:80]+2,2*v2[81:100]+3,4*v2[101:120]+4)+rnorm(n)
v4 <- v2^3
#Para poder emplear la librería ggplot2 es necesario considerar el conjunto de datos como un data.frame
data <- data.frame(factor=v1,x=v2,y=v3,z=v4)
ggplot(data)+
geom_point(aes(x=x,y=y,colour=factor))
Igual que ocurría con la función básica plot
, podemos
modificar el tamaño de los puntos, añadir título al gráfico, modificar
los ejes (con la función labs
), la leyenda (con
scale_.._discrete
), su posición (con theme()
),
o el estilo del gráfico (empleando theme_..
).
ggplot(data)+
geom_point(aes(x=x,y=y,colour=factor))+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman", font=2)+
scale_colour_discrete(name="Tipo",labels=c("1","2","3","4","5","6"))+
theme_minimal()+
theme(legend.position = "top")
Además del color, también podemos modificar la forma de los puntos en
función de alguna variable (con shape
)1.
ggplot(data)+
geom_point(aes(x=x,y=y,shape=factor,colour=factor))+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman", font=2)+
theme_classic()+
theme(legend.position = "left")
También es posible hacer lo mismo con el tamaño de los puntos
(size
). Esta opción puede ser muy útil cuando queremos dar
pesos a nuestros datos (porque no todos son igual de fiables) o
simplemente incorporar otra variable numérica sin pasar a 3D.
Además, podemos eliminar leyendas utilizando la función
guides()
. Para que se puedan diferenciar con claridad los
puntos, se puede utilizar alpha = ..
en la función
geom_point()
para indicar la transparencia de los
puntos.
ggplot(data)+
geom_point(aes(x=x,y=y,colour=factor,size=z),alpha=0.5)+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman", font=2)+
scale_colour_discrete(name="Factor",labels=c("A","B","C","D","E","F"))+
guides(size="none")+
theme_bw()+
theme(legend.position = "bottom")
Podemos representar la recta de regresión de los subconjuntos según
el valor del factor, con la función geom_smooth()
.
ggplot(data)+
geom_point(aes(x=x,y=y,colour=factor),alpha=0.75)+
geom_smooth(aes(x=x,y=y,colour=factor),formula=y~x, method="lm",se=FALSE)+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman", font=2)+
scale_colour_discrete(name="Factor",labels=c("A","B","C","D","E","F"))+
theme_linedraw()
En ambas funciones o capas (geom_point
y
geom_smooth
), la estética es la misma,
aes(x=x,y=y,colour=factor)
, por lo que podemos situarla en
una capa (escribiéndola una única vez). Además, es posible añadir otros
elementos como el intervalo de confianza al nivel de confianza del 99%
(con se=TRUE
y level=0.99
en la función
geom_smooth()
).
ggplot(data)+
aes(x=x,y=y,colour=factor)+
geom_point(alpha=0.75)+
geom_smooth(formula=y~x, method="lm",se=TRUE, level=0.99,)+
labs(title="Diagrama de dispersión",x="x",y="y",family="Times New Roman", font=2)+
scale_colour_discrete(name="Modelo",labels=c("A","B","C","D","E","F"))+
stat_regline_equation(label.x=c(0,0,0,0,0,0),
label.y=c(40,36,32,28,24,20))+
theme_light()
Consideremos el conjunto de datos reales sobre la estructura salarial en España en el año 2018. Sus variables son:
Sexo
: con dos valores
AgnoAnti
: años de antigüedad
SalarioBase
: salario base mensual
Complementos
: complementos salariales recibidos
mensualmente
IRPF
: retenciones IRPF mensuales
BaseSS
: base de cotización a la Seguridad
Social
CotizaSS
: cotización a la Seguridad Social
SalarioBruto
: salario bruto anual
# Lee el conjunto de datos y lo almacena en el objeto data
# Es necesario modificar la ruta de acceso al archivo por la propia
data <- read_excel("/Users/maribelparraarevalo/Library/Mobile Documents/com~apple~CloudDocs/GraficosR/Datos/Salario2018.xlsx")
Si por ejemplo nos interesara comparar la distribución de salarios
por sexo, utilizamos la función geom_histogram()
con la
estética aes(fill=Sexo)
.
ggplot(data)+
aes(x=SalarioBase,fill=Sexo)+
geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Seguramente no se corresponda con el gráfico esperado. Por un lado,
representa histogramas apilados; para que aparezcan superpuestos debemos
dar el valor identity
al argumento position
.
Por otro lado, tal como nos indica el mensaje, por defecto se
representan 30 intervalos que no tiene por qué ser una cantidad adecuada
para nuestro conjunto. Se puede modificar dando otro valor a
bins
(o a center
y/o binwidth
para completar la personalización de los intervalos eligiendo su centro
y anchura, respectivamente) o indicando los puntos de corte en
breaks
.
ggplot(data)+
aes(x=SalarioBase,fill=Sexo)+
geom_histogram(bins=20,position="identity")+
labs(title="Histograma",x="Salario Base",y="")+
guides(colour="none")+
theme_bw()+
geom_freqpoly(bins=20,aes(colour=Sexo))
Además hemos añadido el polígono de frecuencias, con
geom_freqpoly
. Las frecuencias absolutas no suelen ser la
mejor opción a efectos comparativos, especialmente cuando los tamaños de
las muestras son muy diferentes. En estos casos, resulta más adecuado
representar las frecuencias relativas o densidades. Podemos
representarlas simplemente añadiendo la estética
aes(y=..density..)
. Además, hemos añadido
alpha=0.5
para definir transparencia y poder ver ambas
distribuciones, y definido el color de los bordes además del
relleno.
ggplot(data)+
aes(x=SalarioBase,fill=Sexo,colour=Sexo)+
geom_histogram(aes(y=..density..),bins=20,alpha=0.5,position="identity")+
geom_density(alpha=0.5)+
labs(title="Histograma",x="Salario Base",y="")+
guides(colour="none")+
theme_minimal()
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Para tener una imagen más suave de las frecuencias relativas, y que
no dependa de los intervalos utilizados, hemos superpuesto las
densidades estimadas sobre los histogramas añadiendo la capa
geom_density
.
Para apreciar más claramente ambas representaciones, hacemos
transparente el área de la densidad (con alpha=0
) y
modificamos el tipo y color de las líneas añadiendo
aes(linetype=Sexo,colour=Sexo)
.
ggplot(data)+
aes(x=SalarioBase,fill=Sexo,colour=Sexo)+
geom_histogram(aes(y=..density..),bins=20,alpha=0.5,position="identity")+
geom_density(aes(linetype=Sexo,colour=Sexo), alpha=0)+
labs(title="",x="Salario Base",y="")+
theme_classic()
Otra opción es agregar un espacio entre los rectángulos para poder
ver ambos histogramas con position="dodge"
ggplot(data)+
aes(x=SalarioBase,fill=Sexo,colour=Sexo)+
geom_histogram(aes(y=..density..),bins=20,alpha=0.5,position="dodge")+
geom_density(aes(linetype=Sexo,colour=Sexo), alpha=0)+
labs(title="",x="Salario Base",y="")+
theme_classic()
Otra forma de comparar distintos subconjuntos es con diagramas de
caja y bigotes, que se obtienen con geom_boxplot()
.
Vamos a cargar otro conjunto de datos, en este caso con extensión Rdata, sobre hábitos de compras por Internet:
load("/Users/maribelparraarevalo/Library/Mobile Documents/com~apple~CloudDocs/GraficosR/Datos/datosTICr")
Comenzamos representando el diagrama de caja y bigotes para la variable edad, separada por sexo, personalizando su aspecto y añadiendo intervalos de confianza (al 95%) para las medianas:
ggplot(datosTIC,aes(x=Edad,y=Sexo,fill=Sexo,colour=Sexo))+
geom_boxplot(notch=TRUE)
Por defecto no añade las líneas horizontales de los bigotes, pero se
pueden agregar con stat_boxplot
, estableciendo
geom="errorbar"
, y además se puede controlar su ancho con
width
.
ggplot(datosTIC,aes(x=Edad,y=Sexo,fill=Sexo,colour=Sexo))+
stat_boxplot(geom="errorbar",with=0.01)+
geom_boxplot(alpha=0.5)
## Warning in stat_boxplot(geom = "errorbar", with = 0.01): Ignoring unknown
## parameters: `with`
Se pueden añadir otros factores, como por ejemplo la confianza en las TICs
ggplot(datosTIC)+
aes(x=Confianza, y=Edad, colour=Sexo)+
geom_boxplot(notch = TRUE)
ggplot(datosTIC)+
aes(x=Sexo, y=Edad, colour=Confianza)+
geom_boxplot(notch = TRUE)
Cualquiera de los dos gráficos sirve para comprobar que no se
aprecian diferencias significativas entre hombres y mujeres y que las
personas más jóvenes muestran mayor confianza en las TICs, siendo las
personas mayores quienes menos responden a la pregunta (valores
representados como NA
).
Por defecto, los valores de las variables aparecen ordenados
alfanuméricamente. Si queremos modificar dicho orden, para facilitar la
lectura de una representación gráfica se puede usar la función
factor
para reordenarlos según nuestra conveniencia.
Este tipo de representaciones, de algún modo, combinan las cualidades
de los diagramas de caja y bigotes y los histogramas, permitiendo hacer
comparaciones de forma muy rápida y sencilla entre grupos sin prescindir
de los detalles. Lo obtenemos con la función
geom_violin()
.
ggplot(datosTIC)+
aes(x=Sexo,y=Edad, fill=Confianza)+
geom_violin()+
labs(title="Diagrama de violín",x="Sexo",y="Edad")+
theme_bw()
Con las distintas opciones de position
podemos cambiar
la posición relativa de los distintos “violines”. Por ejemplo,
position="identity"
los superpone:
ggplot(datosTIC)+
aes(x=Sexo,y=Edad, fill=Confianza)+
geom_violin(alpha=0.5,position="identity")+
labs(title="Diagrama de violín",x="Sexo",y="Edad")+
theme_bw()
Si queremos que sea horizontal, podemos intercambiar las variables
x
e y
o usar coord_flip
ggplot(datosTIC)+
aes(x=Sexo,y=Edad, fill=Confianza)+
geom_violin(alpha=0.5,position="identity")+
labs(title="Diagrama de violín",x="Sexo",y="Edad")+
coord_flip()+
theme_bw()
Además, se pueden agregar valores como la mediana o la media, junto a
su intervalo de confianza con fun.data
`
ggplot(datosTIC,aes(x=Sexo,y=Edad,
fill=Confianza,colour=Confianza))+
labs(title="Diagrama de violín",x="Sexo",y="Edad")+
geom_violin(alpha=0.5,position="Identity")+
stat_summary(fun.data="mean_cl_boot",geom="pointrange")+
theme_bw()
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `fun.data()`:
## ! The package "Hmisc" is required.
Podemos integrar en ellos la información de varias variables cualitativas o numéricas con pocos valores distintos
ggplot(datosTIC, aes(x=Confianza,fill=UsoInternet))+
geom_bar(position="identity")
Si nos interesa separar por otra variable, incluimos una capa con
facet_wrap
.
ggplot(datosTIC, aes(x=Confianza,fill=UsoInternet))+
geom_bar(position="identity")+
facet_wrap(~Sexo)
Como ya hemos mencionado, ggplot2 se basa en toda una gramática, por lo que el abanico de posibilidades es tan amplio que solo podremos mostrar algunas de ellas. Recomendamos al lector jugar con las distintas funciones y opciones, asignando otros valores para entender mejor su efecto y probar con otras para comprobar cómo es posible obtener cualquier gráfico que nos imaginemos.
El paquete ggplot2 no integra una
funcionalidad específica para combinar varios gráficos en una única
figura, pero existen otras librerías adicionales que sí lo permiten.
Aunque existen varias, aquí trabajaremos con patchwork
que
es la más sencilla de usar.
Comenzamos creando 4 gráficos muy sencillos con los que mostrar las capacidades de la librería.
# Simulación n datos
set.seed(5)
n=100
datos <- data.frame(x=runif(n),
y=rnorm(n))
# Caja y bigotes
g1 <- ggplot(datos, aes(y = y)) +
geom_boxplot()
# Densidad
g2 <- ggplot() +
stat_function(fun = dnorm, geom = "density",
xlim = c(-3, 3), fill = "white")
# Secuencia
g3 <- ggplot(datos, aes(x=x,y = y)) +
geom_line()
# Nube de puntos
g4 <- ggplot(datos, aes(x = x, y = y)) +
geom_point(color="red3")
Si unimos los gráficos con +
patchwork
intentará que la figura resultante sea lo más cuadrada posible:
g1+g2+g3+g4
Para personalizar el número de filas y columnas de la figura se puede
usar la función plot_layout
y para especificar las anchuras
y alturas relativas de los gráficos los argumentos widths
y
heights
, respectivamente.
diseño<-"12
33"
g1+g2+g3+plot_layout(design=diseño)
Una forma equivalente de obtener el mismo resultado
(g1|g2)/g3
Esta variable no tendría por qué ser la misma.↩︎