Plotly permite construir gráficos de alta calidad, incorporando en ellos la interactividad; mostrando botones para hacer zoom en una parte de la gráfica, redefinir los ejes X e Y, mostrar la información que contiene cada dato, mostrar los datos filtrando por uno o varios factores… Además, son gráficos de tipo “responsive”: se adaptan a las dimensiones de la ventana en que aparecen.
Se pueden elaborar gráficos animados de dos formas diferentes:
Directamente con la función plot_ly
Incluyendo un gráfico ya generado con ggplot
como
argumento de la funión plotly
.
Comenzamos programando un gráfico sencillo que muetra un punto que se
mueve de manera aleatoria y uniforme dentro del cuadrado de lado unidad.
Además, lo aprovecharemos para personalizar algunas características de
su aspecto y comenzar a mostrar el potencial de la librería
plotly
:
# Generamos 100 movimientos aleatorios dentro del cuadrado unidad
n=100
mov.ale=data.frame(x=runif(n),y=runif(n),
paso=1:n)
plot_ly(data=mov.ale,x=~x,y=~y,frame=~paso,
type="scatter", mode="markers",
size=5,
width=500, height=500,
symbol=I("circle-dot"),
showlegend=FALSE)
Resulta bastante sencillo añadir más puntos, que distinguimos con diferentes colores:
n=100
np=10
mov.ale=data.frame(x=runif(n*np),y=runif(n*np),
f=rep(1:n,rep(np,n)),p=rep(1:np,n))
plot_ly(data=mov.ale,x=~x,y=~y,frame=~f,
type="scatter", mode="markers",
split=~p, fill=~p,
size=5,
width=600, height=600,
symbol=I("circle-dot"),
showlegend=FALSE)
Con plotly, casi podemos representar cualquier gráfico que podamos imaginar, una vez dominamos su lenguaje. Esto lo facilitan sus múltiples opciones. Durante este curso solo alcanzaremos a mostrar parte de su potencial.
En este segundo ejemplo, supongamos, por ejemplo, que queremos mostrar cómo depende la forma de la distribución normal de su desviación típica:
# valores de la desviación estándar que se mostrarán en la simulación
sigma=c(1/4,1/2,3/4,1,1.25,1.5,1.75)
# valores en los que evaluaremos la función de densidad
x <- seq(-5,5, length.out = 1000)
# creamos los datos a representar en cada paso de la animación
# valoramos la función de densidad para
# los distintos valores de x y cada valor de sigma
aval <- list()
for(step in 1:7){
aval[[step]] <-list(visible = FALSE,
name = paste0('sigma=', sigma[step]),
x=x,
y=1/(sigma[step]*sqrt(2*pi))*exp(-(x/sigma[step])^2/2))
}
# hacermos visible la densidad estándar que
# se mostrará como punto de partida de la animación
aval[5][[1]]$visible = TRUE
# creamos las curvas (una para cada valor de sigma)
steps <- list()
fig <- plot_ly()
fig <- add_annotations(fig, x=-4, y=1.5, "Distribución normal")
for (i in 1:7) {
fig <- add_lines(fig,x=aval[i][[1]]$x, y=aval[i][[1]]$y, visible = aval[i][[1]]$visible,
name = aval[i][[1]]$name, type = 'scatter', mode = 'lines', hoverinfo = 'name',
line=list(color='00CED1'), showlegend = FALSE)
step <- list(args = list('visible', rep(FALSE, length(aval))),
method = 'restyle', label=sigma[i])
step$args[[2]][i] = TRUE
steps[[i]] = step
}
# añadimos el botón de control
fig <- fig %>%
layout(sliders = list(list(active = 4,
currentvalue = list(prefix = "Desviación estándar: "),
pad=sigma,
steps = steps)))
# mostramos la figura
fig
Comenzamos generando un conjunto de datos con varias variables, con distintas distribuciones
n=100
datos<-data.frame(x=1:n,
y1=rnorm(n),
y2=runif(n,0,2),
y3=sample(5,n,rep=TRUE),
y4=rep(-2,n),
y5=rbinom(n,5,2/3))
Representamos las secuencias de datos, personalizando el estilo de cada una de ellas:
plot_ly(data=datos, x=~x) %>%
add_trace(y=~y1, name="Normal", mode='lines') %>%
add_trace(y=~y2, name="Uniforme", mode='lines+markers') %>%
add_trace(y=~y5, name="Binomial", mode='markers')
Otra opción es representar alguno de los conjuntos de datos con los que ya hemos trabajado. Por ejemplo:
# cargamos los datos
library(readxl)
#Importemos el conjunto de datos
data <- read_excel("RiesgoPobrezaTasa.xls")
#un factor
plot_ly(data,x=~riesgo1,y=~riesgo2,type="scatter",mode = "markers+text",color=~ccaa)
Además de las opciones comunes a todas las animaciones, una cuestión interesante es que podemos incluir o eliminar una serie de datos pulsando en la leyenda sobre ella. En el ejemplo, podemos seleccionar o quitar las comunidades autónomas que se muestran. Al situar el cursor sobre un elemento del gráfico (en este caso sobre un punto), obtenemos la información de ese dato (sus coordenadas).
Podemos incorporar una animación con el comando
frame
.
plot_ly(data,x=~riesgo1,y=~riesgo2,type="scatter",color=~ccaa,frame = ~agno)
Si solo nos interesa su forma, podemos representarla de una manera bastante sencilla:
x <- seq(-20, 20, length.out = 201)
y <- x
f<- function(x,y)
{
r=sqrt(x^2+y^2)
sin(r)/r
}
z <- outer(x, y, f)
fig <- plot_ly(z=~z)
fig <- fig %>% add_surface()
fig
Y añadirle algunos detalles más:
fig <- plot_ly(z = ~z) %>% add_surface(
contours = list(
z = list(
show=TRUE,
usecolormap=TRUE,
highlightcolor="#ff0000",
project=list(z=TRUE)
)
)
)
fig <- fig %>% layout(
scene = list(
camera=list(
eye = list(x=1.87, y=0.88, z=-0.64)
)
)
)
fig
Sin embargo, podemos observar que las escalas mostradas en los ejes x e y no son correctas. Para conseguir arreglar este problema, necesitamos complicar un poco el código:
# definimos los ejes
ejex <- list(
nticks = 4,
range = c(-20,20)
)
ejey <- list(
nticks = 4,
range = c(-20,20)
)
ejez <- list(
nticks = 4,
range = c(-1,1)
)
n=101
aux <- seq(-20, 20, length.out = n)
x <- rep(aux,n)
y <- rep(aux,rep(n,n))
f<- function(x,y)
{
r=sqrt(x^2+y^2)
sin(r)/r
}
z <- f(x,y)
fig <- plot_ly(x = ~x, y = ~y, z = ~z, type = 'mesh3d')
fig <- fig %>% layout(scene = list(xaxis=ejex,yaxis=ejey,zaxis=ejez))
fig
library(ggplot2)
###Generamos 50 datos en torno al (3,-4), 50 datos en torno a la N(-2,-4) y los últimos 50
#en torno a (0,0). Fijamos una semilla para poder reproducir los resultados,
set.seed(1234)
x<-matrix(rnorm(300), ncol=2)
x[1:50,1]<-x[1:50,1]+3
x[1:50,2]<-x[1:50,2]-4
x[51:100,1]<-x[51:100,1]-2
x[51:100,2]<-x[51:100,2]-4
#aplicamos el método de k-medias para identificar clusters (agrupaciones de puntos)
km2<-kmeans(x,centers=2,nstart=20) ##forzando 2 clusters
km3<-kmeans(x,centers=3,nstart=20) ##forzando 3 clusters
##definimos el data.frame a usar, las variables km2$cluster y km3$cluster nos dicen en
#qué cluster se encuentra cada dato (toman los valores 1, 2 o 3)
datos<-data.frame(x,as.factor(km2$cluster),as.factor(km3$cluster))
g<-ggplot(datos)+
aes(x=X1,y=X2,colour=as.factor(km3$cluster),shape=as.factor(km2$cluster))+
geom_point()+
labs(title="Clusters",x="x1",y="x2")+
scale_colour_discrete(name="km3")+
scale_shape_discrete(name="km2")
g
#aunque vemos que plotly nos "descoloca" las etiquetas: clasifica cada elemento
#en los dos clusters y muestra los que están clasificados de manera distinta en km2 y km3. Así, los triángulos rojos marcados como (1,2) son los que están en el cluster 1 para la clasificación hecha por km3 y en el 2 para la clasificación km2; los trángulos verdes (2) son los que están en el cluster 2 de km3 y también en el cluster 2 de km3 y los puntos azules (3,1) en el cluster 3 de km3 y cluster 1 de km2.
ggplotly(g)