I am working with ranked-choice voting data in R, and would like to plot it using a Sankey diagram (here is an example). Sankey diagrams default to color-coded nodes for each candidate, but I would like to place an image of each candidate within the nodes instead.
Data and Setup
I have 5 candidates: A, B, C, D, and E, and the ranked preferences of 27 voters (identified through their IDs: 1, 2, 3, ..., 27). This is my initial data:
rcv_data <-
structure(list(pref_voter_id = 1:27, `1` = c("A", "B", "C", "C",
"C", "D", "A", "C", "C", "C", "B", "C", "C", "E", "A", "B", "B",
"A", "B", "C", "C", "C", "B", "E", "D", "B", "E"), `2` = c("C",
"A", "A", "B", "A", "C", "E", "B", "A", "D", "C", "D", "D", "A",
"C", "D", "C", "E", "C", "D", "B", "A", "A", "A", "B", "C", "B"
), `3` = c("B", "C", "D", "E", "B", "E", "B", "A", "B", "A",
"E", "A", "E", "C", "E", "C", "D", "B", "D", "B", "A", "D", "C",
"C", "E", "D", "D"), `4` = c("E", "E", "B", "A", "D", "B", "D",
"D", "D", "B", "D", "B", "B", "D", "B", "E", "A", "D", "E", "A",
"D", "B", "E", "B", "A", "E", "C"), `5` = c("D", "D", "E", "D",
"E", "A", "C", "E", "E", "E", "A", "E", "A", "B", "D", "A", "E",
"C", "A", "E", "E", "E", "D", "D", "C", "A", "A")), row.names = c(NA,
-27L), class = c("tbl_df", "tbl", "data.frame"))
The columns 1, 2, 3, 4, 5 correspond to "first choice", "second choice", ..., "fifth choice" for each voter.
I am using the networkD3
package to create a Sankey diagram in an R Markdown HTML document. To get the data into an appropriate format for the networkD3::sankeyNetwork
function (i.e. in terms of nodes and edges), some wrangling is needed using the rcv
package and the rcv::makde_d3list
function:
library(dplyr)
library(tidyr)
library(rcv)
library(networkD3)
rcv_data %>%
pivot_longer(2:6, names_to = "vote_rank", values_to = "candidate") %>%
rcv::rcv_tally(n_winners = 0) %>% # n_winners is 0 for the diagram to display an extra round
filter(candidate != "NA") %>% # I don't want "NA" to appear in the diagram
rcv::make_d3list() %>%
{networkD3::sankeyNetwork(Links = .$values, Nodes = .$names,
Source = "source", Target = "target",
Value = "value", NodeID = "candidate",
units = "voters", fontSize = 12, nodeWidth = 50)}
Help Needed
Now, I have some files A.jpg, B.jpg, C.jpg, D.jpg, and E.jpg, that contain photos of the 5 candidates. I would like the nodes to include these photos of the candidates, instead of simply being color coded, i.e. instead of dark blue nodes I want the image of candidate C, instead of dark orange nodes I want the image of candiate A etc.
There are two avenues I suspect might lead to a solution:
- The
networkD3::sankeyNetwork
only provides functionality for changing the colors of nodes, but there might be other approaches to the problem using some other R package? I know thevisNetwork
package enables one to add images as nodes, but it doesn't seem to support Sankey diagrams (?). - The
htmlwidgets::onRender
function enables one to add extra JavaScript code to the graph by saving the graph into an object, e.g.graph <- [code above]
, and then writing JavaScript likehtmlwidgets::onRender(graph, JS(...))
. However, I'm not sure what should go in the...
part - how can I access the nodes and attach them to the appropriate images by group?