Introducción

El ggplot2 es un paquete de datos que nos permite realizar diversos tipos gráficos de alta calidad, manipulando con detalle la manera cómo queremos que se vea el gráfico.

Trabaja con objetos tipo data frame para extraer la información que se quiere graficar.

Un ejemplo es un gráfico de barras del porcentaje de personas que tiene o no computadora en su casa. Para ello primero debemos crear la tabla:

library(foreign)
genero12 <- read.spss("IOP_1212_01_D.sav", to.data.frame = TRUE, 
                      use.value.labels = TRUE)

computadora <- prop.table(table(genero12$P81E))*100

computadora
## 
##       Sí       No 
## 45.38591 54.61409

Para generar el gráfico la tabla debe convertirse primero en un data frame:

computadora <- as.data.frame(computadora)
computadora
##   Var1     Freq
## 1   Sí 45.38591
## 2   No 54.61409

Gráfico de barras en ggplot2:

library(ggplot2)

ggplot(computadora, aes(x=Var1, y=Freq)) + geom_bar(stat = "identity")

¿Cómo construir un gráfico en ggplot?: Elementos y pasos

Un gráfico en ggplot se construye combinando una serie de elementos que se añaden en formas de capas y que en su conjunto producirán la forma final del gráfico:

Capa 1: Datos y estética

La primera capa contiene los siguientes elementos:

  • Los datos: El data frame de donde provendrá la información que vamos a graficar.
  • Las estéticas o aes: Son los diversos elementos del gráfico (distancia vertical, distancia horizontal, colores, la forma de un punto o de una línea) que asociaremos con las variables o columnas del data frame. En el ejemplo anterior tenemos que:
  • La distancia horizontal o categorías en el eje x: Var1
  • La distancia vertical en el eje y: Freq
ggplot(computadora, aes(x=Var1, y=Freq))

Si bien hay varias estéticas, las más utilizadas son: + y e y para las información que será puesta en los respectivos ejes horizontal y vertical + colour para el color + shape para la forma de los puntos + fill para el relleno de barras

Capa 2: geoms

Los geoms son instrucciones que nos indican cómo debemos represtar las estéticas en el gráfico, es decir las formas específicas que usaremos para representar los datos: barras, líneas, puntos, cajas, histogramas, densidades, etc. En los geoms también podemos añadir instrucciones específicas. Por ejemplo:

# Gráfico básico
ggplot(computadora, aes(x=Var1, y=Freq)) + 
  geom_bar(stat = "identity")

# Gráfico con colores diferentes para las categorías del eje x
ggplot(computadora, aes(x=Var1, y=Freq, fill=Var1)) + 
  geom_bar(stat = "identity")

# Añadimos una línea de contorno negra para las barras del gráfico
ggplot(computadora, aes(x=Var1, y=Freq, fill=Var1)) + 
  geom_bar(stat = "identity", color = "black")


# Quitamos la leyenda que resulta redundante
ggplot(computadora, aes(x=Var1, y=Freq, fill=Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  guides(fill = FALSE)

Capas 3 en adelante

Las siguientes capas nos permiten personalizar diferentes aspectos del gráfico, tales como:

  • Añadir un geom adicional (por ejemplo líneas o puntos)
  • Especificar los límites inferior y superior de los ejes x e y
  • Etiquetas de los ejes x e y
  • Título del gráfico
  • Texto en coordenadas específicas del gráfico
  • Formato de los textos, leyendas, etiquetas
  • Temas que reúnen algunas plantillas de versiones finales del gráfico.

Por ejemplo si queremos completar el gráfico anterior:

ggplot(computadora, aes(x=Var1, y=Freq, fill=Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  guides(fill = FALSE) +
  ylim(0, 80) + xlab("Tiene equipo") + ylab("% de entrevistados") +
  ggtitle("Porcentaje de estrevistados que declaran tener computadora en el hogar")

El mismo gráfico con un tema en Blanco y Negro:

ggplot(computadora, aes(x=Var1, y=Freq, fill=Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  guides(fill = FALSE) +
  ylim(0, 80) + xlab("Tiene equipo") + ylab("% de entrevistados") +
  ggtitle("Porcentaje de estrevistados que declaran tener computadora en el hogar") +
  theme_bw()

Gráficos de barras múltiples

Para realizar gráficos de barras múltiples, debemos partir de una tabla de frecuencias cruzadas. Por ejemplo, el porcentaje de personas que tienen computadora según nivel socioeconómico del hogar:

comput.2 <- prop.table(table(genero12$P81E, genero12$NSEGrup),2)*100

comput.2
##     
##           A/B        C      D/E
##   Sí 95.81749 65.05682 10.39861
##   No  4.18251 34.94318 89.60139
comput.2 <- as.data.frame(comput.2)
comput.2
##   Var1 Var2     Freq
## 1   Sí  A/B 95.81749
## 2   No  A/B  4.18251
## 3   Sí    C 65.05682
## 4   No    C 34.94318
## 5   Sí  D/E 10.39861
## 6   No  D/E 89.60139
## Barras apiladas

ggplot(comput.2, aes(x=Var2, y=Freq, fill = Var1)) + 
  geom_bar(stat = "identity")

## Barras paralelas, se añade la opción position = position_dodge()

ggplot(comput.2, aes(x=Var2, y=Freq, fill = Var1)) + 
  geom_bar(stat = "identity", position = position_dodge())

Versión final del gráfico:

ggplot(comput.2, aes(x=Var2, y=Freq, fill = Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  xlab("Niveles socioeconómicos") +
  ylab("% de entrevistados") +
  scale_fill_discrete(name = "Tiene equipo") +
  ggtitle("Tenencia de computadora por nivel socioeconómico del entrevistado \nPorcentaje según niveles socioeconómicos") +
  theme_bw()

Otra versión alternativa del gráfico en escala de grises y con subtítulo:

ggplot(comput.2, aes(x=Var2, y=Freq, fill = Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  xlab("Niveles socioeconómicos") +
  ylab("% de entrevistados") +
  scale_fill_brewer(name = "Sexo", palette = "Greys") +
  labs(title = "Tenencia de computadora por nivel socioeconómico del entrevistado",
       subtitle = "% Según niveles socioeconómicos") +
  theme_bw()

Otra versión alternativa del gráfico con colores ad-hoc llenados en forma manual y con subtítulo:

Nota: Para ver más opciones sobre cómo trabajar con colores en gplot2 seguir el siguiente enlace

ggplot(comput.2, aes(x=Var2, y=Freq, fill = Var1)) + 
  geom_bar(stat = "identity", color = "black") +
  xlab("Niveles socioeconómicos") +
  ylab("% de entrevistados") +
  scale_fill_manual(name = "Sexo", values = c("#FF6600", "#330066")) +
  labs(title = "Tenencia de computadora por nivel socioeconómico del entrevistado",
       subtitle = "% Según niveles socioeconómicos") +
  theme_bw()

Histograma y Gráfico de Densidad

Histograma

El geom para histograma es: geom_histogram. Con la opción bindwidht = se puede especificar la amplitud de los intervalos de x que representa cada barra:

# Histograma de amplitud 2 (cada barra representa dos años)

ggplot(genero12, aes(x = EDAD)) + geom_histogram(binwidth = 2, color = "white") + 
  ggtitle("Histograma de Edades de los Entrevistados (intervalos de 2 años)") + xlab("Edades") +
  ylab("Frecuencia") + theme_bw()

# Histograma de amplitud 4 (cada barra representa cuatro años)

ggplot(genero12, aes(x = EDAD)) + geom_histogram(binwidth = 4, color = "white") + 
  ggtitle("Histograma de Edades de los Entrevistados (intervalos de 4 años)") + xlab("Edades") +
  ylab("Frecuencia") + theme_bw()

Gráfico de densidad:

# Densidad simple

ggplot(genero12, aes(x=P19A)) + geom_density() +
  xlab("Horas") + ylab("Densidad") +
  ggtitle("Horas dedicadas a labores domésticas") +
theme_bw()

# Densidad por grupos, diferenciado por colores

ggplot(genero12, aes(x=P19A, color = SEXO)) + geom_density() +
  xlab("Horas") + ylab("Densidad") +
  ggtitle("Horas dedicadas a labores domésticas, según sexo") +
theme_bw()

# Densidad por grupos, diferenciado por tipo de línea y con líneas más gruesas

ggplot(genero12, aes(x=P19A, linetype = SEXO)) + geom_density(size = 2) +
  xlab("Horas") + ylab("Densidad") +
  ggtitle("Horas dedicadas a labores domésticas, según sexo") +
theme_bw()

Boxplot o Gráfico de Cajas

Hagamos el gráfico de cajas del índice de homofobia. Primero hay que calcular el índice:

# Índice de Homofobia
library(dplyr)

homofob <- genero12[, c(111:117)]

homofob <- homofob %>% mutate_if(is.factor, as.numeric)

homofob <- homofob %>% mutate_all(~dplyr::recode(., '5'= NaN))

homofob <- homofob %>% mutate_all(~((. -4)*(-1)))

genero12$i.homofob <- rowSums(homofob)/21*100


# Boxplot simple horizontal

ggplot(genero12, aes(i.homofob)) + geom_boxplot() 

# Boxplot simple vertical

ggplot(genero12, aes(y=i.homofob)) + geom_boxplot() 

Boxplot agrupado por ámbito de residencia:

ggplot(genero12, aes(x=Ambito, y=i.homofob)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  ggtitle("Índice de Homofobia según Ámbito de Residencia") +
  theme_bw()

Boxplot agrupado por ámbito de residencia y grupo de edad

ggplot(genero12, aes(x=Ambito, y=i.homofob, fill = GEDAD)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  ggtitle("Índice de Homofobia según Ámbito de Residencia y Grupos de Edad") +
  scale_fill_discrete(name = "Grupo de Edad") +
  theme_bw()

Gráficos de Barras, Puntos y Líneas para Estadísticos Descriptivos

En este caso usaremos como ejemplo la variable “horas dedicadas a labores domésticas”:

library(doBy)
tab2 <- summaryBy(P19A  ~ SEXO + GEDAD, data = genero12,
          FUN = function(x) {c(Media = mean(x, na.rm = T), 
                               Md = median(x, na.rm = T),
                               Desv = sd(x, na.rm = T), 
                               Rg = range(x, na.rm = T))})

tab2
##        SEXO    GEDAD P19A.Media P19A.Md P19A.Desv P19A.Rg1 P19A.Rg2
## 1 Masculino  18 a 29   13.51232      10  12.67896        0       70
## 2 Masculino  30 a 44   13.70588      10  14.26531        0       84
## 3 Masculino 45 a más   13.89340      10  13.65216        0       70
## 4  Femenino  18 a 29   28.49275      21  25.71650        0      168
## 5  Femenino  30 a 44   34.46701      28  25.04965        0      168
## 6  Femenino 45 a más   33.91905      28  21.82199        0      112
# Gráfico con barras que representan a la media de las horas
# En el título el código "\n" inserta un salto de línea, sirve para cortar títulos largos

ggplot(tab2, aes(x=GEDAD, y=P19A.Media, fill=SEXO)) +
  geom_bar(stat = "identity", position = position_dodge(), color = "black") +
  xlab("Grupos de Edad") + ylab("Horas") + 
  scale_fill_brewer(name = "Sexo", palette = "Greys") + 
  ggtitle("Promedio de horas semanales dedicadas a labores domésticas, \nsegún sexo y grupos de edad") +
  theme_bw()

# Gráfico con puntos que representan a la media de las horas

ggplot(tab2, aes(x=GEDAD, y=P19A.Media, shape=SEXO)) +
  geom_point(size = 3) + ylim(10, 40) +
  xlab("Grupos de Edad") + ylab("Horas") + 
  ggtitle("Promedio de horas semanales dedicadas a labores domésticas, \nsegún sexo y grupos de edad") +
  theme_bw()

Gráfico de puntos y líneas: Horas dedicadas a labores domésticas según número de hijos y sexo del entrevistado

# Primero agrupamos el número de hijos en categorías

library(car)

genero12$hijos.men <- factor(recode(genero12$P44B, 
                                    "NA=0; 1=1; 2=2; 3:hi=3"),
                             labels = c("Ninguno", "Uno", "Dos", "Tres o más"))

tab4 <- summaryBy(P19A ~ SEXO + hijos.men, data = genero12,
          FUN = function(x) {c(Media = mean(x, na.rm = T), 
                               Md = median(x, na.rm = T),
                               Desv = sd(x, na.rm = T), 
                               Rg = range(x, na.rm = T),
                               quantile(x, probs = c(0.25, .75), na.rm=T))})


ggplot(tab4, aes(x=hijos.men, y=P19A.Media, group = SEXO, shape= SEXO, linetype = SEXO)) +
  geom_point(size=3) + geom_line(stat = "identity") + 
  scale_shape_discrete(name = "Sexo") + scale_linetype_discrete(name = "Sexo") +
  ylim(0, 50) + xlab("Número de hijos") + ylab("Horas") +
  ggtitle("Promedio de horas semanales dedicadas a labores \ndomésticas, según número de hijos y sexo del entrevistado") + theme_bw()

Facetas

El ggplot nos permite realizar el mismo gráfico para diferentes grupos de casos en la forma de facetas.

Por ejemplo, según grupo de edad por ámbito de residencia:

# Facetas verticales

ggplot(genero12, aes(x=GEDAD, y=i.homofob)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  xlab("Grupos de edad") +
  ggtitle("Índice de Homofobia según Grupos de Edad, por ámbito de residencia") +
  facet_grid(Ambito ~ .) +
  theme_bw()

# Facetas horizontales

ggplot(genero12, aes(x=GEDAD, y=i.homofob)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  xlab("Grupos de edad") +
  ggtitle("Índice de Homofobia según Grupos de Edad, por ámbito de residencia") +
  facet_grid(.~ Ambito) +
  theme_bw()

# Facetas en forma de reloj

ggplot(genero12, aes(x=GEDAD, y=i.homofob)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  xlab("Grupos de edad") +
  ggtitle("Índice de Homofobia según Grupos de Edad, por dominio geográfico") +
  facet_wrap(~ DOMINIO) +
  theme_bw()

# Facetas que combinan dos variables de agrupación:

ggplot(genero12, aes(x=GEDAD, y=i.homofob)) + geom_boxplot() +
  ylab("Índice de Homofobia") + 
  xlab("Grupos de edad") +
  ggtitle("Índice de Homofobia según Grupos de Edad, por sexo y ámbito de residencia") +
  facet_grid(SEXO ~ Ambito) +
  theme_bw()

Ajustes a los gráficos

El ggplot2, combinado en ocasiones con funciones de otros paquetes, nos permiten hacer diferentes ajustes a la forma en cómo aparecen los datos en el gráfico:

Por ejemplo, etiquetas de categorías muy largas:

tabla2 <- prop.table(table(genero12$P32, genero12$SEXO), 2)*100
tabla2
##                                            
##                                             Masculino  Femenino
##   Hago mucho más de lo que me corresponde    9.393939 32.222222
##   Hago algo más de lo que me corresponde    10.303030 29.722222
##   Hago más o menos lo que me corresponde    45.454545 29.444444
##   Hago algo menos de lo que me corresponde  15.757576  3.611111
##   Hago mucho menos de lo que me corresponde 13.333333  2.500000
##   No contesta                                5.757576  2.500000
tabla2 <- as.data.frame(tabla2)

ggplot(data= tabla2, aes(x=Var1, y=Freq, fill = Var2)) + 
  geom_bar(stat = "identity", position = position_dodge(), color = "black") +
  xlab(" ") + ylab("%") + scale_fill_brewer(name = "Sexo", palette = "Greys") + 
  labs(title = "¿Cuál de las frases siguientes describe mejor la forma en que se reparten \nlas tareas domésticas Ud. y su pareja?, según sexo del entrevistado", subtitle = "% según el sexo del entrevistado") + theme_bw()

# Se puede justificar una etiqueta muy larga usando una función del paquete stringr

library(stringr)

ggplot(data= tabla2, aes(x=Var1, y=Freq, fill = Var2)) + 
  geom_bar(stat = "identity", position = position_dodge(), color = "black") +
  scale_x_discrete(labels = function(x) str_wrap(x, width = 10)) +
  xlab(" ") + ylab("%") + scale_fill_brewer(name = "Sexo", palette = "Greys") + 
  labs(title = "¿Cuál de las frases siguientes describe mejor la forma en que se reparten \nlas tareas domésticas Ud. y su pareja?, según sexo del entrevistado", subtitle = "% según el sexo del entrevistado") + theme_bw()

Existen múltiples opciones usar y elementos que podemos añadir a un gráfico en ggplot para que quede exactamente como queremos que se vea. Un buen lugar donde pueden explorarse varias de esas opciones es la página de gráficos de R Graphics Cookbook que se recomienda revisar al momento de trabajar con gráficos en ggplot.

Exportar gráficos

Para exportar un gráfico podemos grabarlo como un archivo en formato png, lo que nos permite insertarlo en un documento como Word. El comando ggsave nos permite varios ajustes (alto, ancho, calidad) para el archivo gráfico final.

# Guardamos el gráfico como objeto en R:

grafico1 <- ggplot(data= tabla2, aes(x=Var1, y=Freq, fill = Var2)) + 
  geom_bar(stat = "identity", position = position_dodge(), color = "black") +
  scale_x_discrete(labels = function(x) str_wrap(x, width = 10)) +
  xlab(" ") + ylab("%") + scale_fill_brewer(name = "Sexo", palette = "Greys") + 
  labs(title = "¿Cuál de las frases siguientes describe mejor la forma en que se reparten \nlas tareas domésticas Ud. y su pareja?, según sexo del entrevistado", subtitle = "% según el sexo del entrevistado") + theme_bw()


# Grabamos el gráfico en formato png, en forma rectangular 8 x 6

ggsave(filename = "grafico1.png", grafico1, width = 8, height = 6)