A diferencia de los gráficos con el paquete base donde creamos un gráfico a base de pasos sucesivos, ggplot2
se basa en una gramática de gráficos, añadiendo elementos a un graphical device , donde distintos componentes independientes se pueden combinar de muchas maneras diferentes.
Así, ggplot2
fracciona un gráfico en tres partes fundamentales que son: data
, aesthetics
y geometry
, las dos últimas se denominan layers (en general son elementos geométricos y transformaciones estadísticas). Esto nos permite crear gráficos de una forma interactiva, comenzando con los datos que queremos representar y añadiéndole sucesivamente layers que completan y dan forma al gráfico.
Como dice Wickhman: reducir la distancia entre el gráfico pensado y el que estás creando en tu script, nos permite crear gráficos utilizando la misma estructura de pensamiento que empleamos para diseñar un análisis. También nos obliga a pensar un gráfico antes de crearlo, pero esto mismo ocurre cuando queremos llevar a cabo un análisis.
Nota: La gg
del nombre de ggplot2 viene de Grammar of Graphics.
ggplot()
ggplot(data = NULL, mapping = aes(), ..., environment = parent.frame())
data
: un data frameaes
, aesthetics: se emplea para indicar los ejes x e y. También para controlar colores, tamaños, formas, alturas, etc....geometry
: aquí indicaremos el tipo de gráfico (histograma, box plot, líneas,...densidades, puntos,...)Para crear un gráfico con ggplot, lo primero que hay que hacer es definir el conjunto de datos, el sistema de coordenadas y entonces, aplicar una geometría determinada. Este sería el esquema más básico: datos, geometría y sistema de coordenadas ( por defecto el sistema de coordenadas es el cartesiano).
Vamos a verlo paso a paso. Trabajaremos con el dataframe mtcars
, y consideraremos la variable cyl
y gear
como factores:
library(ggplot2)
data(mtcars)
df <- mtcars[ , c("mpg", "cyl", "wt", "gear") ]
df$cyl <- factor( df$cyl )
df$gear <- factor( df$gear )
head(df)
Queremos representar el peso (wp
) frente/relacionada con las millas/galon (mpg
).
En una primera aproximación definimos la parte del origen de datos y los ejes en la función ggplot()
con el argumento aes()
:
ggplot(data = mtcars, aes(x = wt, y = mpg) )
Observamos como en aes
establecemos los ejes, pero en ningún momento hemos especificado un layer de geometría, así que no producirá más que un marco general (ejes cartesianos), sin una geometría especifica.
Este comportamiento nos da una idea de la forma interactiva de trabajar con ggplot2
.
Para añadir layers empleamos el signo +
y continuamos en la siguiente línea del layer:
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_point()
La función geom_point()
admite muchos argumentos, como el tamaño de los puntos (size
), la forma (shape
), el color (color
), etc..
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_point( size=1.5, shape=18, color="red" )
Nota: Hay layers más avanzados que hacen transformaciones de los datos: stat_density()
, stat_count()
,..
Prueba a emplear otros layers de geometrías como geom_line()
:
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_....
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line()
Incluso podemos añadir más de un layer de geometría
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line( linetype=2 ) +
geom_point( col="blue" )
También es posible emplear diferentes orígenes de datos para cada layer. Aunque complica el gráfico, nos ayuda a comprender la potencia de los layers de geometría de ggplot. Presentamos un ejemplo:
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_point( col="blue" ) +
geom_line( data=head(mtcars), color="red" )
Observamos cómo la línea, geom_line()
solo actúa sobre el subconjunto head(mtcars)
.
También podemos hacer cálculos sencillos sobre las variables
ggplot( data = mtcars, aes(x = log(wt), y = log(mpg) )) +
geom_point( col="blue" )
Ejercicio: ¿Puedes anticiparte a lo que estas sentencias producirán?:
ggplot( data = diamonds, aes(carat, price) ) + geom_point()
ggplot( data = economics, aes(date, unemploy) ) + geom_line()
data(diamonds)
data(economics)
data(diamonds)
ggplot( data = diamonds, aes(carat, price) ) + geom_point()
data(economics)
ggplot( data = economics, aes(date, unemploy) ) + geom_line()
En ocasiones conviene parametrizar el sistema de coordenadas, por ejemplo para hacer zoom en una parte del gráfico
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
coord_cartesian(xlim=c(2,5)) +
geom_line()
¿Se te ocurre cómo limitar también el eje de OY, por ejemplo entre 15 y 20?
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
coord_cartesian(xlim=c(2,5), ....) +
geom_line()
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
coord_cartesian(xlim=c(2,5), ylim = c(15,20)) +
geom_line()
Podemos añadir más variables al gráfico introduciendo nuevos aesthetics en la llamada a aes()
Trabajamos con el conjunto de datos mpg
;
class
) a la que pertenezca con colour=class
:
ggplot( data = mpg, aes(cty, hwy, colour=class) ) +
geom_point()
drv
fijando shape= drv
:
ggplot( data = mpg, aes(displ, hwy, colour=class, shape= drv) ) +
geom_point()
ggplot( data = mpg, aes(displ, hwy, colour=class, shape= drv, size=cyl) ) +
geom_point()
Generalmente, diferentes tipos de atributos estéticos trabajan mejor con ciertos tipos de variables, por ejemplo color
y shape
son apropiados para variables categóricas, size
con continuas.
Como dice Hadley Wickham cuando se utilizan elementos estéticos (aesthetics) en un gráfico, menos es normalmente más. Es difícil ver las relaciones simultáneas entre el color, la forma y el tamaño, por lo que hay que ser prudente a la hora de utilizar demasiados aesthetics simultáneamente. En lugar de tratar de hacer una gráfico muy complejo que muestre todo a la vez, hay que intentar, quizás, crear una serie de gráficos simples que cuenten una historia, llevando al lector de la ignorancia al conocimiento.
when using aesthetics in a plot, less is usually more (Hadley Wickham)
Agrupamientos: Como estamos viendo, para añadir más información a un gráfico, en general lo que se hace es añadir más variables en los aesthetics como son: colour
, shape
, fill
, linetype
, fill
, linetypes
y más abruptamente con facets
.
En ocasiones también podemos emplear el argumento group
que suele requerir variables discretas para que ggplot particione con respecto a esa variable. Así la variable de group
debe tener un valor diferente para cada grupo. Como decíamos antes, diferentes argumentos trabajan mejor con diferentes geometrías y las geometrías se comportan mejor o peor, dependiendo del tipo de datos: continuos, discretos, mixtos,...
Otro ejemplo:
ggplot( data = df, aes(mpg, wt, group=cyl, color=cyl) ) +
geom_line()
Observamos cómo un gráfico de líneas hace una línea diferente para cada "grupo". Las hemos coloreado para mejor entendimiento del ejemplo. Pero un efecto parecido podemos obtener jugando con el tipo de línea.
ggplot( data = df, aes(mpg, wt, linetype=cyl) ) +
geom_line()
El enfoque facetting nos permite crear matrices de gráficos seǵun una variable categórica. facetting creará una tabla de gráficos, un gráfico para cada subconjunto. El gráfico se divide en tantas columnas como niveles hay en la variable class con facet_grid(.~class)
ggplot( data = mpg, aes(displ, hwy) ) +
geom_point() +
facet_grid(.~class)
class
con facet_grid(class~.)
ggplot( data = mpg, aes(displ, hwy) ) +
geom_point() +
facet_grid(class~.)
cyl
y columnas como class
con facet_grid(cyl~class)
ggplot( data = mpg, aes(displ, hwy) ) +
geom_point() +
facet_grid(cyl~class)
Podemos añadir líneas verticales u horizontales a un gráfico empleando el layer geom_abline()
y sus derivados: geom_hline()
y geom_vline()
.
Ejercicio: Añade una línea que pase por el punto (0,10) y tenga pendiente m=3, otra vertical que pase por el punto (3,0) y una horizontal que pase por el punto (25,0)
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line() +
geom_abline (aes(intercept=...
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line() +
geom_abline (aes(intercept=10, slope=3), col="red", linetype=2)+
geom_vline(aes(xintercept=3), col="blue", linetype=3)+
geom_hline(aes(yintercept=24),col="purple", linetype=4)
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line() +
geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15))
Podemos rápidamente convertir un segmento en una flecha:
ggplot( data = mtcars, aes(x = wt, y = mpg) ) +
geom_line() +
geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15),
arrow = arrow(length = unit(0.5, "cm")))
En ocasiones debemos de etiquetar el gráfico y los ejes. Para eso disponemos de funciones específicas que sobreescriben lo parametrizado por defecto.
p + ggtitle("Titulo principal")
: añade un título principalp + xlab("Eje 0X")
: Cambia solo la etiqueta del eje de las Xsp + ylab("Eje 0Y")
: Cambia solo la etiqueta del eje de las Ysp + labs(title = "Titulo", x = "Eje 0X", y = "Eje 0Y")
: Todo a la misma vez (esta es la forma más usada)Se puede obligar un salto de línea empleando "\n"
pp <- ggplot( data = df, aes(x = cyl, y = mpg, group = cyl, fill=cyl) ) +
geom_boxplot()
pp
pp <- pp +
labs(title = "Birria de gráfico", x = "Eje 0X: cyl", y = "Eje 0Y: mpg", subtitle = "Un subtitulo..")
pp
Podemos también cambiar el tema de los ejes, incluido el tipo de letra con face
, que puede tomar los valores: "plain", "italic", "bold" y "bold.italic".
pp <- pp +
theme( plot.title = element_text(color="red", size=12, face="bold.italic"),
axis.title.x = element_text(color="blue", size=12, face="bold"),
axis.title.y = element_text(color="#993333", size=12, face="italic")
)
pp
Nota: element_blank()
oculta la etiqueta cuando empleamos theme()
¿Cómo harías para que omitiera la etiqueta del eje OY y sí apareciera la de OX? Emplea la ayuda F1
si es preciso
pp <- pp +
.....
pp
pp <- pp +
xlab("Eje 0X: wt") +
ylab(NULL)
pp
Podemos modificar elementos de la leyenda que ggplot ofrece por defecto. Por ejemplo el título, puesto que crea la leyenda según la variable que pongamos en fill
.
pp + labs(fill = "Nº de \nvelocidades")
pp
También se puede cambiar la posición: "left","top", "right", "bottom", "none". Incluso podemos ser más precisos empleando un vector con componentes que toman valores entre 0 y 1: c(0,0) corresponde a la "parte inferior izquierda" y c(1,1) corresponde a la "parte superior derecha".
pp + theme(legend.position="top")
pp + theme(legend.position = c(0.13, 0.2))
Para no incluir leyenda se puede utilizar la sentencia theme(legend.position = "none")
pp + theme(legend.position = "none")
Hay varias formas de hacerlo, algunas implican el recortado de datos y otras no. Es más recomendable no recortar los datos.
p + coord_cartesian(xlim = c(5, 20), ylim = (0, 50))
: Así hacemos un zoom en el gráfico, sin recortar los datos.p + xlim(5, 20) + ylim(0, 50)
p + scale_x_continuous(limits = c(5,20)) + scale_y_continuous(limits = c(0, 50))
expand_limits()
crea una delgada envoltura alrededor de geom_blank()
que facilita añadir datos al gráfico.p + expand_limits(x = 0, y = 0)
: ajustar el corte de los ejes x e y a (0,0)p + expand_limits(x = c(5, 50), y = c(0, 150))
Probamos estas funciones con el siguiente gráfico de puntos:
data(cars)
q <- ggplot(cars, aes(x = speed, y = dist, col=rep(1:5,10) )) + geom_point()
q
q <- ggplot(cars, aes(x = speed, y = dist, col=rep(1:5,10) )) + geom_point()
q + coord_cartesian(xlim =c(5, 20), ylim = c(0, 50)) +xlab("coord_cartesian")
q + xlim(5, 20) + ylim(0, 50) + xlab("xlim")
q + scale_x_continuous(limits = c(5,20)) + scale_y_continuous(limits = c(0, 50)) + xlab("scale_x_continuous")
q + expand_limits(x = 0, y = 0) + xlab("expand_limits(x=0. u=0...")
q + expand_limits(x = c(5, 50), y = c(0, 150))+ expand_limits("expand_limits(x = c(5, 50)")
library("maps")
spain = map_data('world', region = 'Spain')
ggplot(spain, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = 'white', colour = 'black')
puntos <- data.frame( x=c(2,5,7), y=c(3,5,3) )
ggplot(puntos, aes(x = x, y = y)) +
geom_polygon(colour="red", alpha=0.5)
Por la importancia que tiene el color en un gráfico vamos a ahondar un poco más en este aesthetics ya que, con muy poco más, los resultados puden ser muchísimo mejores.
ToothGrowth$dose <- factor(ToothGrowth$dose)
bp <- ggplot(ToothGrowth, aes(x=dose, y=len)) +
geom_boxplot()
bp
Podemos usar los argumentos estándar de la geometría concreta que estemos empleando y asignarle colores:
bp + geom_boxplot(fill = 'steelblue', color = "red")
O colorear según alguna variable del conjunto de datos para añadir más información
bp + geom_boxplot(aes(fill = dose))
La luminosidad y la intensidad de color de los colores por defecto puede ser modificado usando las funciones scale_hue()
:
bp + geom_boxplot(aes(fill = dose)) +
scale_fill_hue(l=40, c=35)
Aunque también podemos asignar colores manualmente:
bp + geom_boxplot(aes(fill = dose)) +
scale_fill_manual(values=c("#999999", "#E69F00", "#56B4E9"))
Una opción muy interesante es aplicar paletas que combinan colores y que están estudiadas para que queden bien:
library(RColorBrewer)
bp + geom_boxplot(aes(fill = dose)) +
scale_fill_brewer(palette="Dark2")
En el caso de gráficos de líneas o puntos en lugar de scale_fill_brewer()
empleamos scale_color_brewer()
Nos pude ser de utilidad el portal COLORBREWER 2.0 para seleccionar paletas según los criterios que deseemos, por ejemplo "6 colores divergentes" o "6 colores en secuenciales",...
Estas son unas paletas aptas para daltónicos:
# contiene el verde
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
# con color negro
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
scale_fill_manual(values=cbPalette)
o así scale_colour_manual(values=cbPalette)
Una opción muy socorrida es emplear escalas de grises:
bp + geom_boxplot(aes(fill = dose)) +
scale_fill_grey(start=0.8, end=0.2)
Igualmente para gráficos de líneas o puntos emplear en lugar de scale_fill_grey()
scale_color_grey()
También podemos especificar un gradiente entre dos colores:
scale_color_gradient()
, scale_fill_gradient()
para gradientes secuenciales entre dos coloresscale_color_gradient2()
, scale_fill_gradient2()
para gradientes divergentescale_color_gradientn()
, scale_fill_gradientn()
para gradientes secuenciales entre n coloresclass(mtcars$qsec)
sp2 <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point(aes(color = qsec))
sp2
sp2 + scale_color_gradient(low="blue", high="red")
# divergente con un punto medio, la media por ejemplo
mid <- mean(mtcars$qsec)
sp2 + scale_color_gradient2(midpoint = mid, low = "blue", mid = "white", high = "red", space = "Lab" )
Gradientes entre varios colores:
sp2 <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point(aes(color = qsec))
sp2 + scale_color_gradientn(colours = rainbow(5))
Los valores que los argumentos linetype
y shape
pueden tomar son estos:
Ahora puedes practicar lo que has aprendido descargando el siguiente fichero Rmd, abriéndolo con Rstudio
y resolviendo las preguntas de autoevaluación.
Para descargar el Rmd de autoevaluación haz click derecho en el enlace anterior y "Guardar enlace como..." y selecciona dónde quieres guardarlo.
Si al abrirlo con Rstudio observas caracteres extraños, selecciona File/Reopen with encoding/UTF-8
y ya se debe ver bien.
Hay muchos sitios donde encontrar buen material sobre ggplot, nosotros recomendamos el libro de Hadley Wickham por que es fácil de leer, muy didáctico, asequible y se aprende mucho. Un libro intermedio es el de Alboukadel Kassambara que es un manual de acceso rápido a muchos tipos de gráficos. Para ir tirando en momentos de apuros es muy útil la cheat sheet de Rstudio
y el portal de STHDA.
Una vez terminado este documento puede: