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
y
ggpubr
.
library(ggplot2)
library(ggpubr)
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 1 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 utilizarlo:
# 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)[1],2),
"x +",round(coef(regresion)[2],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()
) incluímos las variables x
e
y
, seleccionamos geom_point()
y añadimos la
recta de regresión con geom_smooth
(u otra función de
suavizado), su expresión con stat_regline_equation()
(de la
librería ggpubr
) y el valor del coeficiente de
determinación \(R^2\) con
stat_cor()
. 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, …
# 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(alpha=0.75)+
geom_smooth(formula=y~x, method="lm",se=TRUE,level=0.95)+
labs(title="Scatter plot",x="x",y="y",family="Times New Roman",font=2)+
stat_regline_equation(label.x=7.5,label.y=15) +
stat_cor(aes(label=..rr.label..),label.x=0,label.y=30)
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), por ejemplo.
Generamos un nuevo conjunto de datos, 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))+
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 puntos",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 puntos",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 puntos",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 puntos",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
# Instala la librería readl, caso de que no esté
if(!"readxl" %in% installed.packages())
install.packages("readxl")
# Carga la librería
library(readxl)
# Lee el conjunto de datos y lo almacena en el objeto data
data <- read_excel("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=50,alpha=0.75,position="identity")+
labs(title="Histograma",x="Salario Base",y="")+
guides(colour="none")+
theme_bw()+
geom_freqpoly(binwidth=50,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..)
.
ggplot(data)+
aes(x=SalarioBase,fill=Sexo)+
geom_histogram(aes(y=..density..),bins=50,alpha=0.75,position="identity")+
geom_density()+
labs(title="Histograma",x="Salario Base",y="")+
guides(colour="none")+
theme_minimal()
Para tener una imagen más suave de las frecuencias relativas, y que
no dependa de los intervalos utilizados, se utiliza la densidad. 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)+
geom_histogram(aes(y=..density..),bins=50,alpha=0.75,position="identity")+
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:
load("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%)
ggplot(datosTIC)+
aes(Edad,fill=Sexo)+
geom_boxplot(colour="gray",outlier.colour = "red", notch = TRUE)
y también por su nivel de 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 nos permiten apreciar cómo las
personas más jóvenes muestran mayor confianza en las TICs, siendo las
mayores las que menos responden a la pregunta (valores representados
como NA
).
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 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()
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.
Esta variable no tendría por qué ser la misma.↩︎