Libraries

Waffle chart - Elecciones USA 2016

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"))

Hyperbolic tree - Clasificación Reino Animal

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))