R cuenta con un sistema de generación de gráficas poderoso y
flexible. Para tener una pequeña idea acerca de las opciones disponibles
en el programa base, podemos escribir el comando
demo(graphics)
, aunque su capacidad para crear gráficos de
alta calidad la proporcionan librerías adicionales, algunas de las
cuales trabajaremos más adelante durante el desarrollo del curso. Su
versatilidad es tan grande que resulta imposible detallar todas las
posibilidades de R en términos de generación de representaciones
gráficas, por lo que nos centraremos en las más habituales y/o
versátiles.
plot()
Esta función gráfica ofrece muchas variantes, dependiendo del tipo de objeto al que se aplique (un vector, dos vectores de igual longitud, un data.frame e incluso otros objetos). Es lo que llamamos coerción: la salida depende de los valores que introduzcamos para los argumentos.
Seguramente el caso más simple corresponda a la representación de dos
variables numéricas x
e y
, que nos devolverá
su diagrama de dispersión. Por ejemplo
# 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=2*v1+rnorm(n)
plot(v1,v2)
Podemos personalizar el gráfico, modificando la forma de los puntos,
asignando a pch
1 el valor correspondiente al símbolo que
queramos usar,
el tamaño de dichos símbolos, con cex
(cuyo valor por
defecto es 1),
y también su color, para lo que se dispone de múltiples opciones,
confirmando la enorme versatilidad de R. Por ejemplo con los parámetros
col
y bg
, usando los números del 1 al 8 según
la escala:
con la función colors()
con el valor numérico del color
correspondiente:
el nombre del color2
## [1] "white" "aliceblue" "antiquewhite" "antiquewhite1"
## [5] "antiquewhite2" "antiquewhite3" "antiquewhite4" "aquamarine"
## [9] "aquamarine1" "aquamarine2" "aquamarine3" "aquamarine4"
## [13] "azure" "azure1" "azure2" "azure3"
el valor HEX del color, col = "#0000FF"
3, o bien el valor RGB,
haciendo uso de la función rgb
, que toma la intensidad de
colores rojo, verde y azul como argumentos. Su sintasxis es la
siguiente:
rgb(red, green, blue, alpha, names=NULL, maxColorValue = 1)
`
De forma predeterminada, estos valores se encuentran entre 0 y 1.
Esta configuración predeterminada se puede cambiar con el argumento
maxColorValue
para tener valores entre 0 y el valor que
especifiquemos (maxColorValue = 255
, es el estándar para la
representación del color RGB). Esta función también permite cambiar la
transparencia del color, con el argumento alpha
, que toma
valores desde 0 (completamente transparente) hasta 1 (opaco).
Por ejemplo, vamos a usar círculos rojos rellenos en gris, con un tamaño un tercio inferior a los de la gráfica anterior. La nueva gráfica sería:
plot(v1,v2,pch=21,col="red",bg="gray",cex=2/3)
También podemos ponerle un título y/o un subtítulo y etiquetas a los ejes:
plot(v1,v2,pch=21,col="red",bg="gray",cex=2/3,
main="Mi primer gráfico", xlab="x", ylab="y")
y darle formato al texto con family
y font
(en el siguiente ejemplo elegimos el tipo de letra Times New Roman4 y además
lo destacamos en negrita):
plot(v1,v2,pch=21,col="red",bg="gray",cex=2/3,
main="Mi primer gráfico", xlab="x", ylab="y",
family="serif" , font=2)
R facilita la creación de gráficos más elaborados, añadiendo a los gráficos de alto nivel gráficos de bajo nivel. Por ejemplo, podríamos estar interesados en añadir la recta de regresión muestral, que ajusta por mínimos cuadrados nuestro conjunto de datos, representarla junto a ellos e incluir su expresión:
# 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="Mi primer gráfico", xlab="x", ylab="y",
family="mono" , 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(6,5,paste("y = ",round(coef(regresion)[2],2),
"x +", round(coef(regresion)[1],2)))
Como ya hemos mencionado, la función plot
devuelve
distintos tipos de gráficos según los valores sobre los que la
evaluemos. Por ejemplo, si convertimos la variable v1
en un
factor (as.factor(trunc(v1))
) muestra un diagrama de
barras:
plot(as.factor(trunc(v1)))
Si la evaluamos sobre un único argumento numérico, lo representa como una secuencia:
plot(v1)
que podemos personalizar representando líneas en vez de puntos
plot(v1,type="l")
o ambos
plot(v1,type="b")
con el formato que nos parezca más adecuado para las líneas, gracias
al argumento lty
, según el nombre o código numérico:
plot(v1,type="b",
lty=3, pch=16, col="red")
También nos permite representar una función. Por ejemplo, podemos representar \(f(x)=x \sin^2(x)\) en el intervalo \([0,1]\), añadiendo la expresión matemática como título:
# Definimos la función
f=function(x)
x*sin(x)^2
# Representamos f(x) desde 0 hasta 10
plot(f,0,10, main=expression(f(x)==xsin(x)^2))
También podemos usar plot
como función de bajo nivel (con
add=TRUE
) para representar varias funciones juntas:
# Definimos sendas funciones
f=function(x)
x*sin(x)^2
g=function(x)
2*x*sin(x)^2
# Las representamos desde 0 hasta 10
plot(f,0,10)
plot(g,0,10, add=TRUE, col="red")
El gráfico que aparece por defecto es claramente mejorable. Por
ejemplo, podemos personalizar la región de dibujo, para ver las curvas
completas, personalizando el valor de ylim
# Definimos las funciones
f=function(x)
x*sin(x)^2
g=function(x)
2*x*sin(x)^2
# Las representamos desde 0 hasta 10
plot(f,0,10, ylim=c(0,16))
plot(g,0,10, add=TRUE, col="red")
y añadir una leyenda para identificar las funciones
# Definimos las funciones
f=function(x)
x*sin(x)^2
g=function(x)
2*x*sin(x)^2
# Las representamos desde 0 hasta 10
plot(f,0,10, ylim=c(0,16), lty=2)
plot(g,0,10, add=TRUE, col="red")
legend("topleft", c("f(x)","g(x)"),
col = c("black","red"), lty = c(2, 1),
merge = TRUE, bg = "gray90")
Los gráficos son una herramienta muy potente para representar datos, cuyo principal objetivo suele ser mostrar de una manera visual y simple los posibles patrones presentes en ellos. Para conseguirlo debemos elegir el tipo adecuado, así como su formato. Una mala elección puede ocultar los patrones en vez de mostrarlos. Por ejemplo, supongamos que queremos representar la función \(\sin{i}\), para \(i=1, 2, ..., n\). Si lo hacemos utilizando puntos, con todas las opciones de forma por defecto
n <- 50
x <- 1:n
plot(x,sin(x))
no parece apreciarse ningún patrón. Si cambiamos su aspecto utilizando la misma escala para ambos ejes
n <- 50
x <- 1:n
plot(x,sin(x), asp=1)
el patrón existente sale a la luz. Otra opción podría ser representar líneas en vez de puntos:
n <- 50
x <- 1:n
plot(x,sin(x), type="l")
hist()
La forma habitual de representar un conjunto de datos numérico para
observar su distribución es con un histograma. Podemos crearlo con la
función hist()
, que siempre nos pide como argumento un
vector numérico x
, mientras que el resto son opcionales (al
tener asignados valores por defecto).
# Generamos un conjunto de datos con distribución normal
x=rnorm(100)
# Representamos su distribución
hist(x)
Podemos modificar fácilmente su estilo añadiendo parámetros gráficos
(algunos de los cuales ya conocemos y otros son propios de esta función
como el número de intervalos breaks
o el tipo de
frecuencias representadas freq
, absolutas o relativas)
Cambiar el tipo de frecuencias (absolutas por defecto), solo modifica la escala del eje vertical, pero no la forma del histograma:
# Generamos un conjunto de datos con distribución normal
x=rnorm(100)
hist(x, freq=FALSE)
No ocurre lo mismo cuando forzamos el número de intervalos5 en los que agrupar los valores a representar:
hist(x, freq=FALSE, breaks=20,
main="Histograma",ylab="Frecuencia relativa", col=rgb(0,0.5,0.5))
Como la forma del histograma depende de los intervalos, suele ser muy útil representar su densidad, para poder observar la forma de la distribución de la manera más precisa posible:
hist(x, freq=FALSE, breaks=20,
main="Histograma",ylab="Frecuencia relativa", col=rgb(0,0.75,0.75))
lines(density(x),lty="dotted",lwd=2)
Otra cuestión interesante puede ser comparar el histograma con una
distribución teórica, superponiéndola a éste. En el ejemplo con el que
estamos trabajando, vamos a comparar con la curva de la densidad normal
estándar (que es de la que hemos simulado los valores de
x
):
hist(x, freq=FALSE, breaks=20,
main="Histograma",ylab="Frecuencia relativa", col=rgb(0,0.95,0.95))
curve(dnorm, lty="dotdash",lwd=3, add=TRUE)
Si la muestra fuese más grande, ambas distribuciones se parecerían mucho más:
# Generamos un conjunto de datos mucho más grande con distribución normal estándar
x=rnorm(10^6)
# Representamos el histograma de frecuencias relativas
hist(x, freq=FALSE, breaks=100,
main="Histograma",ylab="Frecuencia relativa")
# Añadimos la curva de la densidad normal estándar
curve(dnorm, add=TRUE, col="red", lwd=2)
Como con cualquier otra función, podemos consultar todas sus opciones
con ?hist()
.
stem
Los diagramas de tallo y hojas son un tipo de representación clásica
de la distribución de datos numéricos, similar a un histograma pero en
formato de texto. Para construirlo, los datos se dividen en tallo
(primer o primeros dígitos del número) y hoja (el resto de dígitos). En
R se pueden crear con la función stem
.
# Generamos un conjunto de datos con distribución normal estándar, no demasiado grande
x=rnorm(10^2)
# Representamos el diagrama de tallo y hojas
stem(x)
##
## The decimal point is at the |
##
## -1 | 9977
## -1 | 4333222222111100
## -0 | 98777766665555
## -0 | 333322111111100
## 0 | 000011111222223333444
## 0 | 556666777889
## 1 | 0000011233344
## 1 | 6788
## 2 |
## 2 | 5
boxplot()
Los boxplot, o diagrama de caja y bigotes, son representaciones gráficas que permiten resumir las principales características de los datos (acerca de su simetría, dispersión, posición y presencia de valores atípicos). La caja comienza en el primer cuartil y termina en el tercero (por lo que contendrá el 50% de los datos centrales), con una línea dentro para representar la mediana. A cada lado de la caja se dibuja un segmento con los datos más alejados, sin contar con los valores atípicos (que aparecen como círculos, caso de existir).
# La siguiente instrucción permite representar una matriz de gráficos
# En este caso, vamos a representar dos gráficos en una fila
par(mfrow=c(1,2))
x=rnorm(100)
# Primer boxplot
boxplot(x)
# Segundo boxplot (con los mismos datos, añadiendo un dato atípico)
boxplot(c(x,5))
Podemos representar los intervalos de confianza al 95% para la
mediana, estableciendo el argumento notch
como
TRUE
.
par(mfrow=c(1,2))
x=rnorm(100)
boxplot(x,notch=TRUE)
# Añadimos un dato atípico
boxplot(c(x,5),notch=TRUE)
Este tipo de gráficos resulta especialmente útil para comparar comportamientos6.
# Generamos sendas secuencias de valores de tres distribuciones
# como si provinieran de distintos procesos A, B y C
xA=rnorm(100,1,2)
xB=rnorm(100,3,1/2)
xC=runif(100,0,6)
datos=data.frame(x=c(xA,xB,xC), Proceso=rep(c("A","B","C"), c(100,100,100)))
boxplot(x~Proceso, data=datos,notch=TRUE)
Una limitación de este tipo de gráficos es que no están diseñados para detectar multimodalidad, por lo que puede ser recomendable combinarlos con el histograma o la curva de densidad 7. Veamos cómo hacerlo con un ejemplo donde concatenamos dos muestras que provienen de distribuciones normales con distintos parámetros:
xA=rnorm(1000,1,1/2)
xB=rnorm(1000,5,2)
x=c(xA,xB)
# Histograma
hist(x,probability=TRUE,
main="", xlab="",ylab="",axes=FALSE,
col=rgb(0.5,0,0.5, alpha=0.5),breaks=40)
# Eje
axis(1)
# Densidad
lines(density(x), col="red", lwd=2)
# Boxplot
par(new=TRUE)
boxplot(x, horizontal=TRUE, axes=FALSE,
col=rgb(0,0,0.15, alpha=0.25))
Otra alternativa para poner de manifiesto la distribución de los
datos es agregar los puntos sobre los diagramas de caja. Podemos hacerlo
con la función stripchart
, especificando
add=TRUE
como argumento.
# Generamos sendas secuencias de valores de tres distribuciones
# como si provinieran de distintos procesos A, B y C
xA=rnorm(100,1,2)
xB=rnorm(100,3,1/2)
xC=runif(100,0,6)
datos=data.frame(x=c(xA,xB,xC), Proceso=rep(c("A","B","C"), c(100,100,100)))
boxplot(x~Proceso, data=datos)
stripchart(x~Proceso, data=datos, add=TRUE,
vertical=TRUE, method="jitter",
pch=1, cex=1/2, col=2:4)
barplot()
y pie()
Cuando una variable es cualitativa o numérica, pero toma pocos valores diferentes, es habitual representarla con un gráfico de barras o de sectores.
# Leemos el conjunto resumido de microdatos del INE sobre uso de TICs
# Si vas a ejecutar la línea siguiente, debes cambiar la ruta mostrada
# por la ruta donde esté alojado el conjunto de datos en tu ordenador
# Si estás en el mismo directorio, solo tendrás que escribir datosTICr
# (el nombre del archivo)
load("/Users/maribelparra/Library/Mobile Documents/com~apple~CloudDocs/GraficosR/Datos/datosTICr")
str(datosTIC)
## 'data.frame': 15027 obs. of 7 variables:
## $ Edad : num 98 71 51 81 76 76 72 59 71 83 ...
## $ Sexo : Factor w/ 2 levels "Hombre","Mujer": 2 2 2 2 1 1 1 1 2 2 ...
## $ Nivel : num 1 1 7 1 1 1 1 3 1 1 ...
## $ NCompras : num NA NA NA NA NA NA NA NA NA NA ...
## $ ValorCompras: num NA NA NA NA NA NA NA NA NA NA ...
## $ UsoInternet : Factor w/ 3 levels "Menos de 3 meses",..: NA NA 1 NA NA NA 1 1 NA NA ...
## $ Confianza : Factor w/ 3 levels "Poco o nada",..: NA NA 2 NA NA NA 1 1 NA NA ...
head(datosTIC)
# Diagrama de barras
barplot(table(datosTIC$Confianza),
col=c("#CCFF99","#FFFF99","#9999FF"))
# Diagrama de sectores
pie(table(datosTIC$Confianza),
col=c("#CCFF99","#FFFF99","#9999FF"))
Podemos incluir un segundo factor y representar un diagrama de barras apiladas de frecuencias absolutas:
x=table(datosTIC$Sexo, datosTIC$Confianza)
barplot(x,
col=c("#CCFF99","#9999FF"))
Añadir una leyenda suele ayudarnos a entender mejor un gráfico
barplot(x,
col=c("#CCFF99","#9999FF"))
legend("topright",legend=c("Hombre","Mujer"),
fil=c("#CCFF99","#9999FF"), title="Sexo")
Si nos interesa representar frecuencias relativas en vez de
frecuencias absolutas o recuentos, usaremos la función
prop.table()
pudiendo elegir si las calculamos por fila
(1), por columna (2) o usando toda la tabla como grupo si no escribimos
nada.
barplot(prop.table(x),
col=c("#CCFF99","#9999FF"))
barplot(prop.table(x,margin=1),
col=c("#CCFF99","#9999FF"))
barplot(prop.table(x,margin=2),
col=c("#CCFF99","#9999FF"))
persp()
Con esta función genérica, R nos facilita la tarea de dibujar gráficos en perspectiva de una superficie sobre el plano x–y.
x <- seq(-20, 20, length.out = 51)
y <- x
f<- function(x,y)
{
r=sqrt(x^2+y^2)
sin(r)/r
}
z <- outer(x, y, f)
persp(x, y, z)
Es sencillo modificar la perspectiva, para apreciar mejor la forma de la superficie
persp(x, y, z, theta = 30, phi = 30)
o el aspecto
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue")
1: La disposición de las pepitas de un girasol sigue un modelo matemático cuyas coordenadas polares para la semilla \(n-\)ésima son: \[ \begin{array}{l} r=n\\ \theta=\frac{137.51 \pi}{180}r \end{array} \] Representar 1000 pepitas con círculos.
n <- 1000
r <- 1:n
theta <- 137.51*pi*r/180
# pasamos a coordenadas cartesianas
x <- cos(theta)*r
y <- sin(theta)*r
plot(x,y,asp=1)
2: Supongamos que se lanzan dos dados: uno negro y otro verde. Vamos a representar cómo varía la estimación de la probabilidad de que el dado negro tenga un valor mayor que el verde.
n=1000
negro <- sample(6, size = n, replace = TRUE)
verde <- sample(6, size = n, replace = TRUE)
p <- cumsum(negro>verde)/(1:n)
plot(p, type = "l", col = "blue",
xlab = "Número de experimentos",
ylab = "Probabilidad",
main = "Convergencia de la simulación"
)
grid()
abline(h = 15/36, col = "red", lwd = 2)
3: Simular puntos dentro de la región \([-4,4]\times[0,1/2]\) y colorear de forma diferente si están por debajo o por encima de la densidad normal estándar.
plot(dnorm, -4, 4, main="Campana de Gauss",
xlab="x", ylab="Densidad de la normal",
col="red", lwd=3)
points(x=c(-4,4), y=c(0,0), type="l") # dibuja eje X
# simulamos n puntos al azar en el recuadro
n=1000
x = runif(n=1000, min=-4, max=4)
y = runif(n=1000, min=0, max=1/2)
points(x, y) # representamos los puntos
color=ifelse(y<dnorm(x), "green", "red")
points(x, y, col=color) # pinto de nuevo con color
4: Vamos a obtener ejemplos de los diferentes tipos de gráficos que se generan dependiendo del tipo de datos que le pasemos como argumento:
par(mfrow = c(2, 3)) # Matriz de gráficos 2x3
# Generamos datos de distintos tipos
n=100
x <- rnorm (n)
y <- rnorm (n)
xt <- ts(matrix(x, nrow = n, ncol = 1),
start = c(2013, 1), frequency = 12)
fechas <- seq(as.Date("2013/1/1"), by = "month", length = n)
factor <- factor(trunc(x))
f <- function(x) x^2
u=runif(n)
tabla=data.frame(v1=u,
v2=u+rnorm(n,0,0.1),
v3=u^2+rnorm(n,0,1/2))
plot(x, y, main = "Gráfico de dispersión")
plot(factor, main = "Diagrama de barras")
plot(factor, x, main = "Diagrama de cajas y bigotes")
plot(xt, main = "Serie temporal")
plot(fechas, x, main = "Gráfico basado en fechas")
plot(f, -5, 5, main = "Función")
par(mfrow = c(1, 1))
plot(tabla, main = "Matriz de correlaciones")
par(mfrow = c(1, 1))
El valor de pch
, en realidad puede ser
cualquier símbolo.↩︎
Para conocer el nombre de todos los colores disponibles
se puede ejecutar la instrucción colors()
.↩︎
Por ejemplo, col=1
,
col="white"
, col="#FFFFFF"
son equivalentes.↩︎
Es necesario que el tipo de letra elegido esté instalada
en nuestro ordenador, porque en otro caso no tendría efecto. Las fuentes
integradas son sans
(Arial), serif
(Times New
Roman), mono
(Courier) y symbol (Standard Symbols L). Es
posible añadir otras con los paquetes extrafont
y
showtext
.↩︎
Los posibles valores de breaks
son un
vector con los puntos de corte (o función que los calcule), un valor
numérico (en cuyo caso R lo redondea al valor más próximo que permita
construir intervalos sencillos) o el nombre del algoritmo que los
calcule ("Sturges"
, "Scott"
,
"Freedman-Diaconis"
).↩︎
Si los intervalos de confianza de dos diagramas no se solapan, significa que hay una fuerte evidencia estadística de que las medianas son diferentes.↩︎
Una opción mejor son los diagramas de violín, que veremos más adelante en el curso.↩︎