En esta visualización, vamos a representar los resultados de las elecciones presidenciales de 2016 en Estados Unidos. Para ello, vamos a utilizar un gráfico de waffle (gofre), que es un tipo de gráfico de barras cuadradas que se utilizan para representar datos proporcionales. Normalmente, consiste en un cuadrado de 10 x 10 celdas, para representar el porcentaje de forma visual (ref). Son una variante del famoso “pie chart”, pero usando cuadrados en lugar de sectores circulares. Una de sus mayores ventajas es que son más fáciles de leer para sectores con porcentajes muy pequeños e, incluso, cuando los porcentajes son parecidos se puede ver la diferencia en el número de celdas (ref). No he visto que tenga un origen específico, pero se ha popularizado en los últimos años con el nombre de “waffle chart”, aunque también se le conoce como “square chart”. Son notables en la visualización de votaciones, encuestas y otros datos proporcionales donde interese representar los pequeños porcentajes de forma visual.
En este caso, vamos a representar el porcentaje de votos obtenido por los candidatos en las elecciones presidenciales de 2016 en Estados Unidos. Para ello, vamos a utilizar los datos del archivo “pres16results.csv”, que contiene los resultados de las elecciones presidenciales de 2016 en Estados Unidos a nivel de condado. El análisis puede ser más granular, pero nosotros vamos a centrarnos en los resultados a nivel nacional.
# Load data
elections <- read.csv("pres16results.csv", sep = ";")
head(elections, 20)
## county fips cand st pct_report votes total_votes
## 1 <NA> US Donald Trump US 0.9951 60350241 127592176
## 2 <NA> US Hillary Clinton US 0.9951 60981118 127592176
## 3 <NA> US Gary Johnson US 0.9951 4164589 127592176
## 4 <NA> US Jill Stein US 0.9951 1255968 127592176
## 5 <NA> US Evan McMullin US 0.9951 451636 127592176
## 6 <NA> US Darrell Castle US 0.9951 180877 127592176
## 7 <NA> US Gloria La Riva US 0.9951 48308 127592176
## 8 <NA> US Rocky De La Fuente US 0.9951 32120 127592176
## 9 <NA> US None of these candidates US 0.9951 28824 127592176
## 10 <NA> US Richard Duncan US 0.9951 23501 127592176
## 11 <NA> US Dan Vacek US 0.9951 13546 127592176
## 12 <NA> US Alyson Kennedy US 0.9951 11456 127592176
## 13 <NA> US Mike Smith US 0.9951 8911 127592176
## 14 <NA> US Chris Keniston US 0.9951 6617 127592176
## 15 <NA> US Lynn Kahn US 0.9951 5565 127592176
## 16 <NA> US Jim Hedges US 0.9951 5525 127592176
## 17 <NA> US Monica Moorehead US 0.9951 3878 127592176
## 18 <NA> US Peter Skewes US 0.9951 3221 127592176
## 19 <NA> US Emidio Soltysik US 0.9951 2471 127592176
## 20 <NA> US Scott Copeland US 0.9951 2347 127592176
## pct lead
## 1 4.729933e-01 Donald Trump
## 2 4.779378e-01 Donald Trump
## 3 3.263985e-02 Donald Trump
## 4 9.843613e-03 Donald Trump
## 5 3.539684e-03 Donald Trump
## 6 1.417618e-03 Donald Trump
## 7 3.786126e-04 Donald Trump
## 8 2.517396e-04 Donald Trump
## 9 2.259073e-04 Donald Trump
## 10 1.841884e-04 Donald Trump
## 11 1.061664e-04 Donald Trump
## 12 8.978607e-05 Donald Trump
## 13 6.983971e-05 Donald Trump
## 14 5.186055e-05 Donald Trump
## 15 4.361553e-05 Donald Trump
## 16 4.330203e-05 Donald Trump
## 17 3.039371e-05 Donald Trump
## 18 2.524449e-05 Donald Trump
## 19 1.936639e-05 Donald Trump
## 20 1.839454e-05 Donald Trump
# Create a data frame with the candidates and percentage of votes
top3_votes_df <- elections %>%
# Filter by US
filter(fips == "US") %>%
select(cand, pct) %>%
# Sum the percentage of votes for each candidate
group_by(cand) %>%
summarise(pct = sum(pct))
# Multiply by 100 to get the percentage
top3_votes_df$pct <- round(top3_votes_df$pct * 100, 0)
# Change names to <name - percentage>
top3_votes_df$cand <- paste(top3_votes_df$cand, "-", top3_votes_df$pct, "%")
# Remove perc 0
top3_votes_df <- top3_votes_df[top3_votes_df$pct > 0, ]
# Create another row with the remaining percentage
top3_votes_df <- rbind(top3_votes_df, data.frame(cand = "Others", pct = 100 - sum(top3_votes_df$pct)))
top3_votes_df
## # A tibble: 5 × 2
## cand pct
## <chr> <dbl>
## 1 Donald Trump - 47 % 47
## 2 Gary Johnson - 3 % 3
## 3 Hillary Clinton - 48 % 48
## 4 Jill Stein - 1 % 1
## 5 Others 1
# Now we will use the data frame top3_votes_df to create a waffle chart
waffle(top3_votes_df, rows = 10, size = 0.5, title = "Presidential election 2016", xlab = "1 cuadrado = 1%", colors = c("blue", "#00BF00", "red", "purple", "grey"))
En esta visualización, vamos a representar la clasificación del reino animal en un árbol hiperbólico. Un árbol hiperbólico o “hypertree” es una forma de visualización jerárquica que se utiliza para representar relaciones jerárquicas entre elementos usando la geometría hiperbólica. En un árbol hiperbólico, los nodos se colocan en un espacio hiperbólico, que es un espacio curvo con propiedades geométricas diferentes al espacio euclidiano. Los árboles hiperbólicos son útiles para visualizar jerarquías complejas, ya que permiten representar una gran cantidad de nodos en un espacio limitado. Además, los árboles hiperbólicos tienen la propiedad de que los nodos cercanos en el árbol están más cerca en el espacio hiperbólico, lo que facilita la navegación y la comprensión de la estructura jerárquica. Fue introducido por primera vez por John Lamping, Ramana Rao y Peter Pirolli en 1995 (ref). Normalmente se usa el modelo de disco de Poincaré para representar el espacio hiperbólico, que es un modelo de proyección de un espacio hiperbólico en un espacio euclidiano, haciendo que todo el árbol sea visible a la vez, haciendo que se vea como un ojo de pez. Como curiosidad, fueron patentados en EEUU por Xerox en 1996, pero la patente expiró. Su uso se da en jerarquías complejas y profundas, como la clasificación de especies, la estructura de un sitio web, la organización de archivos, árboles genealógicos, etc.
En este caso, vamos a representar la clasificación del reino animal en diferentes grupos, como vertebrados e invertebrados, mamíferos, aves, reptiles, peces y anfibios, insectos, arácnidos, moluscos y crustáceos, y diferentes especies de animales. Para ello, vamos a utilizar los datos del archivo “animal_hierarchy.csv”, “subgroup_hierarchy.csv” y “species_hierarchy.csv”, que contienen la jerarquía de los diferentes grupos de animales.
# Create a data frame giving the hierarchical structure of animals
animal_hierarchy <- data.frame(
from = "",
to = c(
"Vertebrates",
"Invertebrates"
)
)
subgroup_hierarchy <- data.frame(
from = c(
rep("Vertebrates", 5), # Mammals, Birds, Reptiles, Fish, Amphibians
rep("Invertebrates", 4) # Insects, Arachnids, Mollusks, Crustaceans
),
to = c(
"Mammals",
"Birds",
"Reptiles",
"Fish",
"Amphibians",
"Insects",
"Arachnids",
"Mollusks",
"Crustaceans"
)
)
species_hierarchy <- data.frame(
from = c(
rep("Mammals", 5), # Lion, Elephant, Tiger, Bear, Wolf
rep("Birds", 3), # Eagle, Owl, Parrot
rep("Reptiles", 3), # Snake, Crocodile, Turtle
rep("Fish", 2), # Shark, Salmon
rep("Amphibians", 3), # Frog, Toad, Newt
rep("Insects", 3), # Ant, Bee, Butterfly
rep("Arachnids", 2), # Spider, Scorpion
rep("Mollusks", 2), # Snail, Octopus
rep("Crustaceans", 2) # Crab, Lobster
),
to = c(
"Lion",
"Elephant",
"Tiger",
"Bear",
"Wolf",
"Eagle",
"Owl",
"Parrot",
"Snake",
"Crocodile",
"Turtle",
"Shark",
"Salmon",
"Frog",
"Toad",
"Newt",
"Ant",
"Bee",
"Butterfly",
"Spider",
"Scorpion",
"Snail",
"Octopus",
"Crab",
"Lobster"
)
)
edges <- rbind(animal_hierarchy, subgroup_hierarchy, species_hierarchy)
# Create a vertices data.frame. One line per animal object in the hierarchy
animal_vertices <- data.frame(
name = unique(c(as.character(edges$from), as.character(edges$to))),
value = runif(length(unique(c(as.character(edges$from), as.character(edges$to)))) ) # Random values for illustration
)
# Add a column with the group of each animal. It will be useful later to color points
animal_vertices$group <- edges$from[match(animal_vertices$name, edges$to)]
# Create a graph object
animal_graph <- graph_from_data_frame(edges, vertices = animal_vertices)
# Make the plot
ggraph(animal_graph, layout = 'dendrogram', circular = FALSE) +
geom_edge_diagonal(colour = "grey") +
scale_edge_colour_distiller(palette = "RdPu") +
geom_node_text(aes(x = x * 1.15, y = y * 1.15, label = name), size = 3, alpha = 1) +
geom_node_point(aes(filter = leaf, x = x * 1.07, y = y * 1.07, colour = group, size = value, alpha = 0.2)) +
scale_colour_manual(values = brewer.pal(9, "Set1")) +
scale_size_continuous(range = c(2, 10)) +
theme_void() +
theme(
legend.position = "none",
plot.margin = unit(c(0, 0, 0, 0), "cm"),
) +
expand_limits(x = c(-1.3, 1.3), y = c(-1.3, 1.3))
ggraph(animal_graph, layout = 'dendrogram', circular = TRUE) +
geom_edge_diagonal(colour = "grey") +
geom_node_text(aes(x = x * 1.15, y = y * 1.15, label = name), size = 3, alpha = 1) +
geom_node_point(aes(filter = leaf, x = x, y = y, colour = group, size = value, alpha = 0.2)) +
scale_colour_manual(values = brewer.pal(9, "Set1")) +
scale_size_continuous(range = c(2, 10)) +
theme_void() +
theme(
legend.position = "none",
plot.margin = unit(c(0, 0, 0, 0), "cm"),
) +
expand_limits(x = c(-1.3, 1.3), y = c(-1.3, 1.3))