graficos de red con igraph
Los gráficos de red son un tipo de diagramas en los que se pintan las relaciones entre nodos, por lo que sirven para representar datos con vínculos cruzados tipo red.
Vamos a explicar cómo realizar un gráfico de red con la librería igraph
, como siempre en R, tenemos varias opciones y librerías que los hacen, pero esta me ha parecido bastante buena y con opciones de personalización suficientes.
igraph
La pasada semana realizamos un ejemplo de gráfica Sankey, y en cierta forma los gráficos de red son el tipo generalizado de gráficos Sankey, con muchas más opciones.
La librería igraph es muy completa, tiene mil opciones de personalización y trazado, hay también muchas web con información de cómo hacer estos gráficos, por ejemplo aquí, pero la introducción y la forma de organizar los datos puede ser el mayor impedimento para usarlos, así que voy a hacer un ejemplo completo con datos de flujo de agua.
Los datos que quiero representar son la producción y reparto de agua desde la fuente de origen, hasta los usuarios finales en una red. Estos datos se ofrecen en cantidades mensuales y quiero hace un resumen gráfico de red para el informe mensual de turno.
Los datos originales obtenidos de una Excel y son los siguientes, e indican la producción y flujo desde la planta desaladora de origen a cada destino:
origen | destino | punto_destino | Volumen | Grupo |
---|---|---|---|---|
16 | 15 | Captacion planta | 12155.437 | PLANTA |
1 | 2 | C.RR.A planta | 64.585 | C.RR.A |
1 | 3 | C.RR.A Salinares | 682.884 | C.RR.A |
14 | 4 | C.RR.A Fuente del Pobre | 442.198 | C.RR.A |
14 | 5 | C.RR.A toma nueva | 307.868 | C.RR.A |
1 | 6 | C.RR.P Toma1 | 125.661 | C.RR.P |
14 | 7 | C.RR.P bombeo | 453.680 | C.RR.P |
14 | 8 | C.RR.P Toma vagon | 384.699 | C.RR.P |
1 | 9 | Ayuntamiento | 0.000 | Ayuntamiento |
13 | 10 | C.RR.T | 685.458 | C.RR.T |
13 | 11 | C.RR.T2 | 272.581 | C.RR.T |
13 | 12 | C.RR.L | 1942.262 | C.RR.L |
14 | 13 | Embalse | 2900.301 | PLANTA |
1 | 14 | Bombeo | 4614.407 | PLANTA |
15 | 1 | Producto planta | 5361.876 | PLANTA |
1 | 16 | Mar | 6793.561 | PLANTA |
Grafico de red
Con estos datos lo importante es que disponemos de una relación de enlaces en las columnas 1 y 2 que nos indican el origen y destino de la producción. Además disponemos de los datos de los nodos de la red, que en este caso es la misma tabla de datos original, pero que en caso de tener relaciones dobles será otra tabla similar con la descripción de cada nodo y algunas variables importantes.
Vamos a crear dos tablas una de enlaces y otra de nodos:
library(igraph)
##
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
# tabla de enlaces
enlaces<-data.frame(stringsAsFactors=FALSE,
from = c(16, 1, 1, 14, 14, 1, 14, 14, 1, 13, 13, 13, 14, 1, 15, 1),
to = c(15, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 16))
# tabla de nodos
nodos<-data.frame(stringsAsFactors=FALSE,
to = c(15, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 16),
punto_destino = c("Captacion planta", "C.RR.A naranjos", "Balsa C.RR.A",
"Fuente Pobre", "Toma nueva C.RR.A",
"C.RR.P 1", "C.RR.P bombeo", "C.RR.P 2", "Ayuntamiento",
"C.RR.T", "C.RR.T 2", "C.RR.L", "Embalse", "Bombeo",
"Producto planta", "Mar"),
Volumen = c("12155.437", "64.585", "682.884", "442.198", "307.868",
"125.661", "453.680", "384.699", "0.000", "685.458", "272.581",
"1942.262", "2900.301", "4614.407", "5361.876", "6793.561"),
Grupo = c("PLANTA", "C.RR.A", "C.RR.A", "C.RR.A", "C.RR.A",
"C.RR.P", "C.RR.P", "C.RR.P", "Ayuntamiento", "C.RR.T",
"C.RR.T", "C.RR.L", "PLANTA", "PLANTA", "PLANTA", "PLANTA"))
# convierto en hm3 la variable de volumen
nodos$Volumen<-as.numeric(nodos$Volumen)/1000
# Creo la red con la función graph_from_data_frame
red <- graph_from_data_frame(enlaces, directed=TRUE, vertices=nodos)
# vemos la estructura e= enlaces o edge, v= vertices o nodos
print(red, e=TRUE, v=TRUE)
## IGRAPH feb5536 DN-- 16 16 --
## + attr: name (v/c), punto_destino (v/c), Volumen (v/n), Grupo
## | (v/c)
## + edges from feb5536 (vertex names):
## [1] 16->15 1 ->2 1 ->3 14->4 14->5 1 ->6 14->7 14->8 1 ->9 13->10
## [11] 13->11 13->12 14->13 1 ->14 15->1 1 ->16
# tambien podemos ver los enlaces o edge
E(red)
## + 16/16 edges from feb5536 (vertex names):
## [1] 16->15 1 ->2 1 ->3 14->4 14->5 1 ->6 14->7 14->8 1 ->9 13->10
## [11] 13->11 13->12 14->13 1 ->14 15->1 1 ->16
# y los nodos o V
V(red)
## + 16/16 vertices, named, from feb5536:
## [1] 15 2 3 4 5 6 7 8 9 10 11 12 13 14 1 16
# pinto la red
plot(red)
Ya tenemos montada la red básica, pero el gráfico deja mucho que desear.
Buscamos algo más visual y fácil de interpretar, y lo conseguimos con los parámetros gráficos de la red. Veremos que hay parámetros para los nodos (vertex) y para los enlaces (edge), con lo que podemos personalizar la forma de enlaces, color, tamaño del nodo etc., vamos a ello:
par(mfrow=c(1,1), mar=c(0,0,1,0))
# Ajusto algunos parametros de la red
plot(red,vertex.label= nodos$punto_destino,
vertex.color="lightblue",
vertex.size=nodos$Volumen*2,
edge.arrow.size=1,edge.color="darkblue",
edge.curved=.1,
edge.width=nodos$Volumen*3)
Esto ya tiene otra pinta, pero vamos a seguir intentando mejoras
# creamos unos colores
#library("RColorBrewer")
#pal3 <- brewer.pal(10, "Set3")
#colrs <- rev(pal3)
# Reamos colores personalizados
colrs <- c("gray50", "tomato", "gold", "orange", "green","lightblue")
# creamos una variable con los colores en los vertices
V(red)$color<-colrs[as.factor(nodos$Grupo)]
#V(red_aguilas)$label<-"" #Paste0(punto_destino$nombre,"f")
# tambien creamos otra variable para eltamñano del nodo que dependa del volumen
V(red)$size <- nodos$Volumen
# para conservar la forma, se puede dar un formato específico con layout_with... y varias opciones
l <- layout_with_fr(red)
plot(red,layout=l,main="Distribución agua en la red - feb 2019",
vertex.label= paste(nodos$punto_destino,"\n",signif(nodos$Volumen,digits=2),"Hm3"),
vertex.label.cex=.7,
vertex.label.color="black", # V(red)$color,
vertex.color= V(red)$color,
vertex.size=nodos$Volumen*2,
edge.color=V(red)$color,
edge.curved=.1,
edge.width=nodos$Volumen*2
)
# añadimos la leyenda
legend(x=-1, y=1.1,levels(as.factor(nodos$Grupo)), pch=21,
col="#777777", pt.bg=colrs, pt.cex=2, cex=.8, bty="n", ncol=1)
El gráfico anterior expresa de manera bastante clara el flujo de producción que hemos tenido el mes de febrero de 2019. Es un ejemplo de uso de gráficos de red bastante simple, pero estos diagramas están pensados para grupos y tablas mucho más complejos y proporcionan herramientas de selección y trazado profesionales.
Por ver solo un ejemplo más, con la opción de cluster podemos agrupar automáticamente los datos:
# creamos un cluster optimo de los datos automático
clp <- cluster_optimal(red)
# anañimos el resultado anterior como nueva variable de los vertices
V(red)$grup1 <- clp$membership
colorescluster <- adjustcolor( c("blue", "tomato", "gold"), alpha=.6)
plot(red,
vertex.size=15,
vertex.color=colorescluster[V(red)$grup1],
vertex.label.cex=0.5,
vertex.label= paste(nodos$punto_destino,"\n",signif(nodos$Volumen,digits=2),"Hm3")
)