This is for 2026-06-22

library(tidyverse)

tidyverse author - package edgelist from

vct_packages <- c("dplyr", "ggplot2", "ellmer",
                        "tidyr", "tidymodels", "recipes",
                        "readr", "tibble", "stringr", "forcats",
                        "purrr", "lubridate")

# data cleaning
package_author_edgelist <- 
  as_tibble(tools::CRAN_package_db()) |>
  filter(Package %in% vct_packages) |>
  mutate(Author = str_replace_all(Author, ' \\[|\\]', "*" )) |>
  select(Package, Author) |>
  mutate(Author = map(Author, ~ str_split_1(.x,"\n"))) |>
  unnest() |> 
  mutate(Author = Author |> str_remove('\\*.+' )) |>
  mutate(Author = Author |> str_trim()) |>
  filter_out(Author |> str_detect("orcid.org")) |>
  filter_out(Author == "Posit Software, PBC") |>
  filter_out(Author == "Posit, PBC")

head(package_author_edgelist)
## # A tibble: 6 × 2
##   Package Author         
##   <chr>   <chr>          
## 1 dplyr   Hadley Wickham 
## 2 dplyr   Romain François
## 3 dplyr   Lionel Henry   
## 4 dplyr   Kirill Müller  
## 5 dplyr   Davis Vaughan  
## 6 ellmer  Hadley Wickham

ggraph_to_threejs first cut

Notes: Some reasons why the function isn’t totally robust or satisfying…

library(tidyverse)
library(ggraph)
library(igraph)
library(threejs)
library(tidygraph)

ggraph_to_threejs <- function(edgelist = package_author_edgelist, 
                              plot = last_plot()){
    
  g <-  edgelist |> select(1:2) |> as.matrix() |> 
    graph_from_edgelist()
  
  node_data <- layer_data(i = 2, plot = plot)
  
  graph_attr(g, "layout") <- NULL    
    
  node_id <- V(g) |> names()
  
  joined <- tibble(node_id) |> 
    left_join(node_data, by = "node_id")
  
  from_list <- edgelist |> pull(1)
  
  V(g)$size <- joined$size/3.66
  V(g)$shape <- joined$label
  V(g)$color <- joined$colour
   
  graphjs(g = g, bg = "gray10",  
          showLabels = T,  
          layout = list(  
            layout_with_fr(g, dim = 3)),  
                    main = "")

}

my_edgelist <- tribble(~v1,~v2,
        "A","B",
        "A","C",
        "A","D",
        "B","C")

my_edgelist |>
  ggraph(layout = "kk") +
  geom_edge_link() + 
  geom_node_label(aes(
    node_id = name, # just for threejs
    label = name, 
    color = name == "A"))

my_edgelist |>
  ggraph_to_threejs(plot = last_plot()) #< the three js versions..
theme_set(theme_gray())

tv_tidygraph <- package_author_edgelist |> 
  tidygraph::as_tbl_graph() |>
  mutate(is_package = name %in% vct_packages)

tv_tidygraph |> 
  ggraph(layout = "kk") +
  geom_edge_link() +
  geom_node_label(aes(label = name, 
                      node_id = name, # for conversion to threejs
                      color = is_package))

library(threejs)
library(igraph)

package_author_edgelist |> 
  ggraph_to_threejs(plot = last_plot())
tv_tidygraph |> 
  ggraph(layout = "kk") +
  geom_edge_link() + 
  geom_node_text(aes(
    node_id = name, # just for threejs
    label = is_package |> ifelse("📦", "🧠"), 
    color = is_package |> ifelse("tan", "pink") |> I()))

ggraph_to_threejs(package_author_edgelist)
tv_tidygraph |> 
  ggraph(layout = "kk") +
  geom_edge_link() + 
  geom_node_text(aes(
    size = !is_package,
    node_id = name, # just for threejs
    label = is_package |> ifelse("📦", "🏃🏽"), 
    color = is_package |> ifelse("tan", "tan") |> I())) + 
  scale_size(range = c(3,8))

ggraph_to_threejs(package_author_edgelist)

reasons not to pursue extracting the edgelist??

layer_data() |> head()
##   PANEL         x          y group      index edge_colour edge_width
## 1     1 -1.290417 -0.4899154     1 0.00000000       black        0.5
## 2     1 -1.275734 -0.4861394     1 0.01010101       black        0.5
## 3     1 -1.261051 -0.4823633     1 0.02020202       black        0.5
## 4     1 -1.246368 -0.4785872     1 0.03030303       black        0.5
## 5     1 -1.231685 -0.4748111     1 0.04040404       black        0.5
## 6     1 -1.217002 -0.4710351     1 0.05050505       black        0.5
##   edge_linetype edge_alpha start_cap end_cap label label_pos label_size angle
## 1         solid         NA        NA      NA    NA       0.5       3.88     0
## 2         solid         NA        NA      NA    NA       0.5       3.88     0
## 3         solid         NA        NA      NA    NA       0.5       3.88     0
## 4         solid         NA        NA      NA    NA       0.5       3.88     0
## 5         solid         NA        NA      NA    NA       0.5       3.88     0
## 6         solid         NA        NA      NA    NA       0.5       3.88     0
##   hjust vjust family fontface lineheight
## 1   0.5   0.5               1        1.2
## 2   0.5   0.5               1        1.2
## 3   0.5   0.5               1        1.2
## 4   0.5   0.5               1        1.2
## 5   0.5   0.5               1        1.2
## 6   0.5   0.5               1        1.2
last_plot() + 
  geom_point(data = layer_data(), aes(x = x, y = y), shape = "|")