En la entrada anterior nos centramos en los gráficos de desviación, los cuales suelen ser de los más comunes en análisis de datos. En ésta parte nos vamos a centrar en los gráficos de correlación, los cuales serán los que se usen principalmente cuando trabajemos con estadística, pronosticos, inteligencias artificiales, redes neuronales, econometría, etc. Éstos gráficos son esencialmente útiles cuando queremos ver la correlación entre dos variables cuantitativas, ya que nos muestran el valor de \(Y\) dado un valor de \(X\) o \(Z\). Existen casos en los que podemos hacer un gráfico de tres dimensiones para analizar la correlación de una variable dependiente respecto a dos variables independientes, aunque no suelen ser tan comunes, pero los veremos a continuación.
Para éste ejercicio utilizaremos los siguientes paquetes:
library(readxl)
library(corrplot)
library(corrgram)
library(datasets)
library(gapminder)
library(plotly)
library(ggplot2)
library(gganimate)
library(GGally)
library(highcharter)
library(echarts4r)
library(tidyverse)
Ggplot2
Estos gráficos son los más comunes y simples cuando vemos la relación de dos variables, ya que simplemente nos muestran los puntos entre dos ejes y como es que éstos conectan. Veamos un ejemplo de ello con la base precarga de R USArrests
a continuación:
# Leemos la base
attach(USArrests)
head(USArrests)
## Murder Assault UrbanPop Rape
## Alabama 13.2 236 58 21.2
## Alaska 10.0 263 48 44.5
## Arizona 8.1 294 80 31.0
## Arkansas 8.8 190 50 19.5
## California 9.0 276 91 40.6
## Colorado 7.9 204 78 38.7
Vamos a ver qué relación tienen las variables de Murder
, Assault
, UrbarnPop
y Rape
entre si.
# Gráfico 1
ggplot(USArrests, aes( x = Murder, y = Assault) ) +
geom_point(size = 1.0, color = "darkblue") +
theme_bw() +
theme(legend.position = "none") +
theme(legend.title = element_blank()) +
guides(col = guide_legend(nrow = 1, byrow = TRUE)) +
xlab("Asesinatos") +
ylab("Asaltos")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,1,1,1), "cm")) +
labs(
title = "Asesinatos vs Asaltos",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de USAarrests. \nNotas: Espero que te ayude este ejercicio."
)
# Gráfico 2
ggplot(USArrests, aes( x = Murder, y = UrbanPop) ) +
geom_point(size = 1.0, color = "darkblue") +
theme_bw() +
theme(legend.position = "none") +
theme(legend.title = element_blank()) +
guides(col = guide_legend(nrow = 1, byrow = TRUE)) +
xlab("Asesinatos") +
ylab("Población")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,1,1,1), "cm")) +
labs(
title = "Asesinatos vs Población",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de USAarrests. \nNotas: Espero que te ayude este ejercicio."
)
# Gráfico 3
ggplot(USArrests, aes( x = Murder, y = Rape) ) +
geom_point(size = 1.0, color = "darkblue") +
theme_bw() +
theme(legend.position = "none") +
theme(legend.title = element_blank()) +
guides(col = guide_legend(nrow = 1, byrow = TRUE)) +
xlab("Asesinatos") +
ylab("Violaciones")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,1,1,1), "cm")) +
labs(
title = "Asesinatos vs violaciones",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de USAarrests. \nNotas: Espero que te ayude este ejercicio."
)
echarts4r
Alternativamente, podemos utilizar éste paquete si queremos tener un gráfico más manejable que, además, es interactivo. Veamos un ejemplo usando los mismos datos:
# Gráfico de puntos
USArrests %>%
e_charts(x = Murder) %>%
e_scatter(Assault, name = "Asaltos") %>%
e_axis_labels(x = "Asesinatos", y = "Asaltos") %>%
e_title(
text = "Asesinatos vs asaltos",
subtext = "Espero que te sirva este codigo"
) %>%
e_x_axis(
nameLocation = "center",
splitArea = list(show = FALSE),
axisLabel = list(margin = 3),
axisPointer = list(
show = TRUE,
lineStyle = list(
color = "#999999",
width = 0.75,
type = "dotted"
)
)
) %>%
e_y_axis(
nameLocation = "center",
splitArea = list(show = FALSE),
axisLabel = list(margin = 0),
axisPointer = list(
show = TRUE,
lineStyle = list(
color = "#999999",
width = 2,
type = "dotted"
)
)
)
Ahora, si quisieramos realizar un modelo de regresión lineal para conocer la linea de tendencia que mejor se ajusta a los datos, podríamos hacerlo con la función e_lm()
, de la siguiente manera:
# Gráfico de puntos con MCO
USArrests %>%
e_charts(x = Murder) %>%
e_scatter(Assault, name = "Asaltos") %>%
e_lm(Assault ~ Murder, name = "Modelo") %>%
e_axis_labels(x = "Asesinatos", y = "Asaltos") %>%
e_title(
text = "Asesinatos vs asaltos",
subtext = "Espero que te sirva este codigo"
) %>%
e_x_axis(
nameLocation = "center",
splitArea = list(show = FALSE),
axisLabel = list(margin = 3),
axisPointer = list(
show = TRUE,
lineStyle = list(
color = "#999999",
width = 0.75,
type = "dotted"
)
)
) %>%
e_y_axis(
nameLocation = "center",
splitArea = list(show = FALSE),
axisLabel = list(margin = 0),
axisPointer = list(
show = TRUE,
lineStyle = list(
color = "#999999",
width = 2,
type = "dotted"
)
)
)
Tenemos la posibilidad de agregar un botón de zoom además, para mejorar la visualización de los datos, con la función e_datazomm()
. Vamos a convertir el gráfico anterior en un objeto y apliquemos la función:
grafico1 %>%
e_datazoom(
type = "slider",
toolbox = TRUE,
bottom = -5)
highcharter
Finalmente, también podemos utilizar éste paquete para graficar nuestros datos de una manera aún más sencilla. Basta con escribir el siguiente código:
# Gráfico de puntos
highchart() %>%
hc_title(text = "Asaltos vs asesinatos") %>%
hc_chart(type = "scatter") %>%
hc_xAxis(Murder) %>%
hc_add_series(Assault, name = "Relación")
Además, éste gráfico nos permite hacer zoom en la parte que queramos aplicando la función hc_chart(zoomType = "xy")
de la siguiente manera:
highchart() %>%
hc_title(text = "Asaltos vs asesinatos") %>%
hc_chart(zoomType = "xy") %>%
hc_chart(type = "scatter") %>%
hc_xAxis(Murder) %>%
hc_add_series(Assault, name = "Relación")
A pesar de no ser tan comunes, los gráficos de puntos en 3 dimensiones pueden ser útiles cuando queremos comparar la relación entre una variable dependiente y dos independientes. Es importante mencionar que los el límite de dimensiones para un gráfico es 3, más allá de eso es imposible graficar los datos en un solo plot.
Pasemos al ejemplo utilizando el paquete echarts4r
nuevamente:
USArrests %>%
e_charts(Murder) %>%
e_scatter_3d(Assault, Rape, smooth = TRUE) %>%
e_visual_map()
Estos gráficos tienen una mejor visualización cuando los hacemos de éstilo superficie, como por ejemplo:
USArrests %>%
e_charts(Murder) %>%
e_surface(Assault, Rape, smooth = TRUE) %>%
e_visual_map()
Este tipo de gráficos son esencialmente útiles si queremos hacer una comparación entre, por ejemplo, una tasa de cambio (la línea) y un monto/cantidad (las barras). Por ejemplo, supongamos que queremos saber la relación existente entre el PIB observado en México y sus tasas de cambio trimestrales de los últimos 10 años, vamos a hacer un ejercicio sencillo con datos de Inegi.Como siempre, comenzamos leyendo la base de datos para saber lo que tenemos para graficar:
# Cargamos y leemos la base de datos
pibtasa <- read_excel("/Users/jorge/Downloads/pibtasa.xlsx")
attach(pibtasa)
head(pibtasa)
## # A tibble: 6 x 3
## Periodo PIB Variacion
## <dttm> <dbl> <dbl>
## 1 2011-01-01 00:00:00 14902733. 3.69
## 2 2011-04-01 00:00:00 15413046. 2.76
## 3 2011-07-01 00:00:00 15526015. 4.05
## 4 2011-10-01 00:00:00 16139540. 4.13
## 5 2012-01-01 00:00:00 15619753. 4.81
## 6 2012-04-01 00:00:00 16027465. 3.99
Como vemos, tenemos el periodo, el PIB observado en millones de pesos, con su respectiva tasa de cambio en porcentaje, por lo que si graficamos observaríamos lo siguiente:
pibtasa %>%
e_charts(Periodo) %>%
e_bar(PIB) %>%
e_line(Variacion, name = "Variación anual",
y_index = 1) %>%
e_tooltip() %>%
e_title("PIB vs tasa de cambio", "Espero que te sirva este ejercicio")
Como podemos observar, al hacer un gráfico de doble eje y podemos tener una comparación más justa, ya que veríamos el valor observado del PIB en un cierto periodo, además de su variación anual respecto al mismo trimestre del año anterior.
Ahora bien, si lo preferimos, podemos hacer uso de un gráfico de área para visualizar mejor a las tasas de cambio de la siguiente manera:
pibtasa %>%
e_charts(Periodo) %>%
e_bar(PIB) %>%
e_area(Variacion, name = "Variación anual",
y_index = 1) %>%
e_tooltip() %>%
e_title("PIB vs tasa de cambio", "Espero que te sirva este ejercicio")
Esto ya dependerá de los datos y el gusto del lector.
Una comparación interesante que se puede realizar es graficar las tasas de cambio trimestrales vs tasas de cambio anuales, ya que es una buena forma de tener perspectiva estadística sobre si realmente estamos creciendo o solo es una recuperación debido a una alta caída del trimestre anterior. Usaremos una base de datos identica a la anterior, solo que en éste caso usaremos unicamente tasas de cambio (trimestrales vs anuales):
# Cargamos y leemos la base de datos
pibtasa2 <- read_excel("/Users/jorge/Downloads/pibtasa2.xlsx")
attach(pibtasa2)
## The following objects are masked from pibtasa:
##
## Periodo, PIB
head(pibtasa2)
## # A tibble: 6 x 4
## Periodo PIB `Variacion anual` `Variación trimestral`
## <dttm> <dbl> <dbl> <dbl>
## 1 2012-01-01 00:00:00 15619753. 4.81 -3.22
## 2 2012-04-01 00:00:00 16027465. 3.99 2.61
## 3 2012-07-01 00:00:00 15952811. 2.75 -0.466
## 4 2012-10-01 00:00:00 16638865. 3.09 4.30
## 5 2013-01-01 00:00:00 15719787. 0.640 -5.52
## 6 2013-04-01 00:00:00 16361864. 2.09 4.08
Ahora, graficamos los datos:
pibtasa2 %>%
e_charts(Periodo) %>%
e_bar(`Variación trimestral`) %>%
e_area(`Variacion anual`, name = "Variación anual") %>%
e_tooltip() %>%
e_title("Tasa anual vs trimestral", "Espero que te sirva este ejercicio")
Gracias a éste tipo de gráficos podemos tener una comparación más realista de los datos que tenemos, ya que comparar con diferentes periodos puede darnos una idea erronea o sesgada.
Estos son básicamente los mismos que vimos en el punto 1, con la diferencia de que los datos ahora están unidos por una linea. Este tipo de gráficos suelen ser útiles cuando queremos ver como ha cambiado la relación de dos variables a lo largo del tiempo, sin embargo no es recomendable utilizarlos a menos que estemos trabajando con series de tiempo o una base de datos con pocas observaciones, ya que sería complicado ver datos muy dispersos a lo largo del tiempo. Para ilustrar ese problema vamos a hacer un gráfico de puntos conectados con los datos de UsArrests
a continuación:
USArrests %>%
e_charts(Assault) %>%
e_line(Rape) %>%
e_tooltip() %>%
e_title("Asaltos vs violaciones", "Espero que te sirva este ejercicio")
Como podemos observar, los datos son bastante dispersos, por lo que no se puede ver tan claramente una tendencia o relación en el tiempo.
Donde si es recomendable utilizar éste tipo de gráficos es en las series de tiempo, como por ejemplo con los datos del PIB usados anteriormente:
pibtasa %>%
e_charts(Periodo) %>%
e_line(PIB) %>%
e_tooltip() %>%
e_title("PIB en el tiempo", "Espero que te sirva este ejercicio")
En este caso al no tener información tan diversa si podemos ver una tendencia en el tiempo y poder sacar conclusiones respecto a ello.
Estos gráficos son una forma algo más específica de los gráficos de puntos, ya que ahora los mismos puntos tendrán diferentes tamaños, ya que el tamaño estaría representando otra variable.
Indiscutiblemente, la mejor forma de hacer gráficos de burbuja es mediante la libreria ggplot2
, ya que además podemos jugar con los gráficos y hacer más cosas, como volverlos interactivos, crear un gif, etc.
Vamos a ver un ejemplo con los datos gapminder
provenientes de la libreria del mismo nombre. Como siempre comencemos leyendo y visualizando la base de datos, para entender mejor la lógica de lo que haremos después:
# Leyendo la base de datos
attach(gapminder)
head(gapminder)
## # A tibble: 6 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Afghanistan Asia 1957 30.3 9240934 821.
## 3 Afghanistan Asia 1962 32.0 10267083 853.
## 4 Afghanistan Asia 1967 34.0 11537966 836.
## 5 Afghanistan Asia 1972 36.1 13079460 740.
## 6 Afghanistan Asia 1977 38.4 14880372 786.
Como vemos, tenemos una serie de observaciones para diferentes años y diferentes países sobre el PIB per cápita, la esperanza de vida y la población. En este caso vamos a graficar el PIB per cápita (gdpPercap
) respecto a la esperanza de vida (lifeExp
), siendo que el tamaño de las burbujas estará determinado por la cantidad de población de cada país. Vamos al ejercicio:
# Filtramos la base a un año en específico
basefiltrada <- filter(gapminder, year == "1952")
head(basefiltrada)
## # A tibble: 6 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Albania Europe 1952 55.2 1282697 1601.
## 3 Algeria Africa 1952 43.1 9279525 2449.
## 4 Angola Africa 1952 30.0 4232095 3521.
## 5 Argentina Americas 1952 62.5 17876956 5911.
## 6 Australia Oceania 1952 69.1 8691212 10040.
# Cambiamos el órden de la población a descendente
basefiltrada <- arrange(basefiltrada, desc(pop))
# Creamos el gráfico
ggplot(basefiltrada, aes(x=gdpPercap, y=lifeExp, size = pop)) +
geom_point(alpha= 0.4) +
scale_size(range = c(.1, 15), name="Población") +
theme_bw() +
theme(legend.title = element_blank()) +
guides(col = guide_legend(nrow = 1, byrow = TRUE)) +
xlab("PIB per cápita") +
ylab("Esperanza de vida")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,.5,1,1), "cm")) +
labs(
title = "Gráfico de burbujas",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de gapminder. \nNotas: Espero que te ayude este ejercicio."
)
Aún podemos hacer algo más. Podemos coloreear las burbujas por continente con la función color = continent
dentro de la función aes()
, omitiendo la función guides()
, de la siguiente manera:
ggplot(basefiltrada, aes(x=gdpPercap, y=lifeExp, size = pop, color = continent)) +
geom_point(alpha= 0.4) +
scale_size(range = c(.1, 15), name="Población") +
theme_bw() +
theme(legend.title = element_blank()) +
xlab("PIB per cápita") +
ylab("Esperanza de vida")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,1,1,1), "cm")) +
labs(
title = "Gráfico de burbujas",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de gapminder. \nNotas: Espero que te ayude este ejercicio."
)
¿Y si quisiéramos volverlo interactivo? Muy sencillo, simplemente creamos un objeto con el código anterior al que podremos nombrar, por ejemplo, bubblegraph
y mediante la librería plotly
creamos el gráfico interactivo de la siguiente manera:
# Creamos el objeto
bubblegraph <- ggplot(basefiltrada, aes(x=gdpPercap, y=lifeExp, size = pop, color = continent)) +
geom_point(alpha= 0.4) +
scale_size(range = c(.1, 15), name="Población") +
theme_bw() +
theme(legend.title = element_blank()) +
xlab("PIB per cápita") +
ylab("Esperanza de vida")+
theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) +
theme(plot.subtitle = element_text(size = 10, hjust = 0)) +
theme(plot.caption = element_text(size = 10, hjust = 0)) +
theme(plot.margin = unit(c(1,1,1,1), "cm")) +
labs(
title = "Gráfico de burbujas",
subtitle = "Ejercicio de correlación.",
caption = "Fuente: Elaboración propia con datos de gapminder. \nNotas: Espero que te ayude este ejercicio."
)
# Creamos el gráfico interactivo
ggplotly(bubblegraph)
Nótese que no alteramos nada del código anterior, simplemente agregamos al principio bubblegraph <-
para crear el objeto y poder trabajar con él.
La base original contenía diversos años y originalmente lo que hice fue filtrarla para solo escoger uno a graficar, pero ¿y si quisieramos graficar todos a la vez? Obviamente esto no es posible en un solo gráfico, pero en una animación si lo es, ya que se crearían múltiples gráficos a la vez que pasarían uno tras otro. Para ésta parte utilizaremos la librería gganimate
y haremos el mismo gráfico que antes, solo que ahora usaremos la base original. Vamos con el ejercicio:
# Creamos la animación
ggplot(gapminder, aes(x=gdpPercap, y=lifeExp, size = pop, color = continent)) +
geom_point(alpha= 0.4) +
scale_size(range = c(.1, 15), name="Población") +
theme_bw() +
labs(title = 'Year: {frame_time}', x = 'PIB per capita', y = 'Expectativa de vida') +
transition_time(year) +
ease_aes('linear')
Hemos llegado a la última parte de esta entrada con probablemente la mejor forma de representar la correlación de varias variables mediante un gráfico, utilizando un gráfico de mapa de correlación, en donde la variación en colores/números nos indicará que tan fuerte es ésta respecto a una variable en específco. Para éste ejercicio vamos a usar la base de datos attitude
del paquete datasets
, ya que contiene una gran cantidad de variables y podremos representar de mejor manera el gráfico de correlación.
En éste caso tenemos diversas maneras y paquetes para hacer un gráfico de correlación. Podemos ir a lo más simple y analizar la covarianza de los datos con una matriz, por ejemplo:
# Leemos la base
attach(attitude)
head(attitude)
## rating complaints privileges learning raises critical advance
## 1 43 51 30 39 61 92 45
## 2 63 64 51 54 63 73 47
## 3 71 70 68 69 76 86 48
## 4 61 63 45 47 54 84 35
## 5 81 78 56 66 71 83 47
## 6 43 55 49 44 54 49 34
# Matriz de correlación
cor(attitude)
## rating complaints privileges learning raises critical
## rating 1.0000000 0.8254176 0.4261169 0.6236782 0.5901390 0.1564392
## complaints 0.8254176 1.0000000 0.5582882 0.5967358 0.6691975 0.1877143
## privileges 0.4261169 0.5582882 1.0000000 0.4933310 0.4454779 0.1472331
## learning 0.6236782 0.5967358 0.4933310 1.0000000 0.6403144 0.1159652
## raises 0.5901390 0.6691975 0.4454779 0.6403144 1.0000000 0.3768830
## critical 0.1564392 0.1877143 0.1472331 0.1159652 0.3768830 1.0000000
## advance 0.1550863 0.2245796 0.3432934 0.5316198 0.5741862 0.2833432
## advance
## rating 0.1550863
## complaints 0.2245796
## privileges 0.3432934
## learning 0.5316198
## raises 0.5741862
## critical 0.2833432
## advance 1.0000000
No hemos hecho un gráfico hasta ahora, pero primero hay que entender la lógica de lo que haremos. Una matriz de correlación nos dice que tan correlacionadas-valga la redundancia-están dos variables. Obviamente al comparar una variable con ella misma siempre tendremos una relación perfecta, es por ello que la matriz identidad siempre es una diagonal llena de 1’s. La correlación va de 0 a 1, entre más cercana se encuentre a 1, las variables tendrán una mayor relación entre ellas. Entendiendo lo anterior, entonces podemos comenzar a graficar una matriz de correlación. Podemos hacerlo con el paquete corrplot
, pero para ello primero tenemos que convertir el Data Frame a matriz de correlación con la función corrgram
del paquete con el mismo nombre:
# Creamos la matriz de correlación
correjemplo <- corrgram(attitude)
# Creamos el gráfico de correlación
corrplot(correjemplo, method = "circle")
# Podemos cambiar la estética de los círculos de la siguiente manera:
# Cuadrados
corrplot(correjemplo, method = "square")
# Números
corrplot(correjemplo, method = "number")
# De pastel
corrplot(correjemplo, method = "pie")
# Por colores
corrplot(correjemplo, method = "color")
# O cambiar la paleta de colores
corrplot(correjemplo, method = "circle", col = c("blue", "green"))
# Podemos crear solo un lado del correlograma
corrplot(correjemplo, method = "color", type ="upper")
# O al revés
corrplot(correjemplo, method = "color", type ="lower")
Hasta ahora hemos hecho diferentes tipos de correlogramas, pero aún podemos llevarlo más lejos y hacer uno que además nos proporcione información estadística, como la distribución de cada variable usando la función pairs()
del paquete ggally
, tal que:
# Creamos el gráfico con información estadística
ggpairs(attitude)
En este último caso haremos un gráfico de correlación interactivo con el ya conocido paquete echarts4r
de la siguiente manera:
# Creamos el gráfico usando la matriz de correlación hecha previamente
correjemplo %>%
e_charts() %>%
e_correlations(
visual_map = TRUE,
order = "hclust",
inRange = list(color = c('#edafda', '#eeeeee', '#59c4e6')),
itemStyle = list(
borderWidth = 2,
borderColor = "#fff"
)
) %>%
e_title("Matriz de orrelación", "Espero que te ayude este ejercicio")
Si llegaste hasta esta parte quiero agradecerte, ya que probablemente te tomó bastante tiempo de leer y practicar para poder replicar los gráficos aquí expuestos. ¡Gracias por tomarte la molestia de leer esta entrada!
Wickham, H. (2011). ggplot2. Wiley Interdisciplinary Reviews: Computational Statistics, 3(2), 180-185.
Wickham, H., Chang, W., & Wickham, M. H. (2016). Package ‘ggplot2’. Create Elegant Data Visualisations Using the Grammar of Graphics. Version, 2(1), 1-189.
Kuan, J. (2015). Learning Highcharts 4. Packt Publishing Ltd.
Shahid, B. (2014). Highcharts essentials. Packt Publishing Ltd.
Bivand, R. S., Pebesma, E. J., Gomez-Rubio, V., & Pebesma, E. J. (2013). Applied spatial data analysis with R (Vol. 2). New York: Springer.
Gardiner, A. (1976). Homogeneoys graphs. Journal of Combinatorial Theory, Series B, 20(1), 94-102.