threadleR is an R client for Threadle, a high-performance network engine. It starts a background Threadle process, sends commands, and returns results back to R. Most functions are thin wrappers around Threadle CLI commands.
Install from GitHub:
Load the package:
th_is_available() checks whether the
threadle executable can be found on your system.
If it returns FALSE, either add threadle to your PATH or start Threadle with an explicit path:
Threadle has its own working directory. Many file-based commands
(especially th_load_file()) depend on it.
To inspect Threadle working directory:
To set it:
To keep Threadle aligned with the current R working directory:
Threadle network files may reference companion files (e.g., a nodeset file). When you load a network from disk, Threadle will also try to load the referenced nodeset file using its current working directory.
th_start_threadle()
th_sync_wd()
#> Set current working directory to '/Users/doge/Documents/threadleR/vignettes'.
#> Threadle working directory synced to: /Users/doge/Documents/threadleR/vignettes
exdir <- th_stage_examples_to_wd(folder = "threadle_examples", overwrite = TRUE)
th_set_workdir(exdir)
#> Set current working directory to '/Users/doge/Documents/threadleR/vignettes/threadle_examples'.
list.files(exdir)
#> [1] "dscw_nodeset.tsv" "dscw.tsv"
#> [3] "lazega_female_nodeset.tsv" "lazega_female.tsv"
#> [5] "lazega_nodes.tsv" "lazega.tsv"
#> [7] "mynet_nodesetfile.tsv" "mynet.tsv"
#> [9] "mynodes.tsv"net_file <- file.path(exdir, "lazega.tsv")
lazega <- th_load_file("lazega", net_file, type = "network")
#> Set current working directory to '/Users/doge/Documents/threadleR/vignettes/threadle_examples'.
#> Loaded structure 'lazega' from 'lazega.tsv'
#> Set current working directory to '/Users/doge/Documents/threadleR/vignettes/threadle_examples'.
# th_load_file("lazega", ..., type = "network") also creates:
# lazega_nodeset (a threadle_nodeset handle in the calling environment)
th_i()
#> Inventory contains 2 structure(s)
#> $lazega
#> [1] "Network"
#>
#> $lazega_nodeset
#> [1] "Nodeset"
th_info(lazega)
#> Returning metadata about 'lazega'
#> $Type
#> [1] "Network"
#>
#> $Name
#> [1] "lazega"
#>
#> $Filepath
#> [1] "lazega.tsv"
#>
#> $isModified
#> [1] FALSE
#>
#> $Nodeset
#> [1] "Lawyers"
#>
#> $Layers
#> Name Mode Directionality ValueType SelftiesAllowed NbrEdges
#> 1 friends 1 Directed Binary FALSE 575
#> 2 advice 1 Directed Binary FALSE 892
#> 3 collaboration 1 Undirected Binary FALSE 378
th_info(lazega_nodeset)
#> Returning metadata about 'Lawyers'
#> $Type
#> [1] "Nodeset"
#>
#> $Name
#> [1] "Lawyers"
#>
#> $Filepath
#> [1] "lazega_nodes.tsv"
#>
#> $isModified
#> [1] FALSE
#>
#> $NbrNodes
#> [1] 71
#>
#> $NodeAttributes
#> Name Type
#> 1 Status Char
#> 2 Gender Char
#> 3 Office Char
#> 4 YearsWithFirm Int
#> 5 Age Int
#> 6 Practice Char
#> 7 LawSchool Charth_preview(lazega, maxlines = 20)
#> Preview of IStructure 'lazega'
#> [1] "Network: lazega"
#> [2] "Nodeset: Lawyers"
#> [3] " friends [1-mode: Binary,Directed,False); Nbr edges:575]"
#> [4] "1 -> 2"
#> [5] "1 -> 4"
#> [6] "1 -> 8"
#> [7] "1 -> 17"
#> [8] "2 -> 16"
#> [9] "2 -> 17"
#> [10] "2 -> 22"
#> [11] "2 -> 26"
#> [12] "4 -> 2"
#> [13] "4 -> 3"
#> [14] " advice [1-mode: Binary,Directed,False); Nbr edges:892]"
#> [15] "1 -> 2"
#> [16] "1 -> 17"
#> [17] "1 -> 20"
#> [18] "2 -> 1"
#> [19] "2 -> 6"
#> [20] "2 -> 17"
#> [21] "2 -> 20"
#> [22] "2 -> 22"
#> [23] "2 -> 24"
#> [24] "2 -> 26"
#> [25] " collaboration [1-mode: Binary,Undirected,False); Nbr edges:378]"
#> [26] "1 <-> 17"
#> [27] "1 <-> 39"
#> [28] "1 <-> 40"
#> [29] "1 <-> 41"
#> [30] "17 <-> 1"
#> [31] "17 <-> 19"
#> [32] "17 <-> 22"
#> [33] "17 <-> 24"
#> [34] "17 <-> 25"
#> [35] "17 <-> 26"
th_i()
#> Inventory contains 2 structure(s)
#> $lazega
#> [1] "Network"
#>
#> $lazega_nodeset
#> [1] "Nodeset"Create a layer and add a few edges:
th_add_layer(lazega, "friends2", mode = 1, directed = FALSE, valuetype = "binary")
#> Layer 'friends2' added to network 'lazega'
th_add_edge(lazega, "friends2", node1id = 1, node2id = 2)
#> Added edge between 1 and 2 (value=1) in layer 'friends2'.
th_add_edge(lazega, "friends2", node1id = 2, node2id = 3)
#> Added edge between 2 and 3 (value=1) in layer 'friends2'.
th_check_edge(lazega, "friends2", node1id = 1, node2id = 2)
#> [1] TRUE
th_get_all_edges(lazega, "friends2", offset = 0, limit = 10)
#> Returning all 2 edge(s) in layer 'friends2':
#> node1 node2 value
#> 1 1 2 1
#> 2 2 3 1Remove an edge or clear a layer:
th_add_layer(lazega, "clubs", mode = 2)
#> Layer 'clubs' added to network 'lazega'
th_add_hyper(lazega, "clubs", hypername = "group1", nodes = c(1, 2, 3))
#> Added hyperedge 'group1' (with 3 nodes) in layer 'clubs'.
th_get_node_hyperedges(lazega, "clubs", nodeid = 1)
#> Node '1' is affiliated to the following hyperedges in layer 'clubs':
#> [1] "group1"
th_get_hyperedge_nodes(lazega, "clubs", hypername = "group1")
#> Hyperedge 'group1' connects the following nodes in layer 'clubs':
#> [1] 1 2 3
th_add_aff(lazega, "clubs", nodeid = 4, hypername = "group1")
#> Node '4' affiliated to hyperedge 'group1' in 2-mode layer 'clubs'.
th_remove_aff(lazega, "clubs", nodeid = 4, hypername = "group1")
#> Node '4' no longer affiliated to hyperedge 'group1' in 2-mode layer 'clubs'.
th_get_all_hyperedges(lazega, "clubs", offset = 0, limit = 10)
#> Returning all 1 hyperedge(s) in layer 'clubs':
#> [1] "group1"Add a node to the nodeset:
Define an integer attribute and set values:
th_define_attr(lazega_nodeset, "score", "int")
#> Node attribute 'score' of attrType Int defined.
th_set_attr(lazega_nodeset, nodeid = 1, attrname = "score", attrvalue = 10)
#> Attribute 'score' for node 1 set to 10.
th_get_attr(lazega_nodeset, nodeid = 1, attrname = "score")
#> [1] 10
th_get_attr_summary(lazega_nodeset, "score")
#> $AttributeName
#> [1] "score"
#>
#> $AttributeType
#> [1] "Int"
#>
#> $Statistics
#> $Statistics$Mean
#> [1] 10
#>
#> $Statistics$Median
#> [1] 10
#>
#> $Statistics$StdDev
#> [1] 0
#>
#> $Statistics$Min
#> [1] 10
#>
#> $Statistics$Max
#> [1] 10
#>
#> $Statistics$Q1
#> [1] 10
#>
#> $Statistics$Q3
#> [1] 10
#>
#> $Statistics$Count
#> [1] 1
#>
#> $Statistics$Missing
#> [1] 71
#>
#> $Statistics$PercentageWithValue
#> [1] 1.388889Remove values or undefine the attribute:
th_remove_attr(lazega_nodeset, nodeid = 1, attrname = "score")
#> Attribute 'score' removed for node 1.
th_undefine_attr(lazega_nodeset, "score")
#> Node attribute 'score' is no longer defined.Generate random attributes:
th_generate_attr(lazega_nodeset, "x", attrtype = "int", min = 1, max = 10)
#> Node attribute 'x' (integer) defined and random values between 1 and 10 assigned to all nodes.
th_get_attr_summary(lazega_nodeset, "x")
#> $AttributeName
#> [1] "x"
#>
#> $AttributeType
#> [1] "Int"
#>
#> $Statistics
#> $Statistics$Mean
#> [1] 5.416667
#>
#> $Statistics$Median
#> [1] 6
#>
#> $Statistics$StdDev
#> [1] 2.711857
#>
#> $Statistics$Min
#> [1] 1
#>
#> $Statistics$Max
#> [1] 10
#>
#> $Statistics$Q1
#> [1] 3
#>
#> $Statistics$Q3
#> [1] 8
#>
#> $Statistics$Count
#> [1] 72
#>
#> $Statistics$Missing
#> [1] 0
#>
#> $Statistics$PercentageWithValue
#> [1] 100Compute density (for a one-mode layer):
Degree (writes an attribute):
th_degree(lazega, "friends", attrname = "deg", direction = "both")
#> Node attribute 'deg' set for 72 nodes in nodeset 'Lawyers'.
th_get_attr(lazega, nodeid = 2, attrname = "deg")
#> [1] 14Connected components (writes component IDs to an attribute):
th_components(lazega, "friends", attrname = "comp")
#> $NbrComponents
#> [1] 4
#>
#> $ComponentSizes
#> [1] 69 1 1 1
th_get_attr_summary(lazega, "comp")
#> $AttributeName
#> [1] "comp"
#>
#> $AttributeType
#> [1] "Int"
#>
#> $Statistics
#> $Statistics$Mean
#> [1] 0.08333333
#>
#> $Statistics$Median
#> [1] 0
#>
#> $Statistics$StdDev
#> [1] 0.4330127
#>
#> $Statistics$Min
#> [1] 0
#>
#> $Statistics$Max
#> [1] 3
#>
#> $Statistics$Q1
#> [1] 0
#>
#> $Statistics$Q3
#> [1] 0
#>
#> $Statistics$Count
#> [1] 72
#>
#> $Statistics$Missing
#> [1] 0
#>
#> $Statistics$PercentageWithValue
#> [1] 100Shortest path:
Export a layer to an edge list:
out <- tempfile(fileext = ".tsv")
th_export_layer(lazega, "friends", file = out, header = TRUE, sep = "\t")
#> Exported layer 'friends' to file: /var/folders/ws/ns45p4ns4kd7jd3xk6t47h1w0000gn/T//RtmprstflM/file13fbee117edf.tsv
readLines(out, n = 3)
#> [1] "from\tto" "1\t2" "1\t4"
unlink(out)Import edges into an existing layer:
tmp <- tempfile(fileext = ".tsv")
write.table(
data.frame(node1 = c(1, 2), node2 = c(2, 3), value = c(1, 1)),
file = tmp, sep = "\t", row.names = FALSE, col.names = FALSE, quote = FALSE
)
th_import_layer(lazega, "friends",
file = tmp, format = "edgelist",
node1col = 0, node2col = 1, valuecol = 2,
header = FALSE, sep = "\t"
)
#> Imported edgelist to 1-mode layer 'friends'
th_check_edge(lazega, "friends", node1id = 1, node2id = 2)
#> [1] TRUE
unlink(tmp)Save nodeset or network:
tmp_net <- tempfile(fileext = ".tsv")
th_save_file(lazega, file = tmp_net)
#> Saved network 'lazega' to file: /var/folders/ws/ns45p4ns4kd7jd3xk6t47h1w0000gn/T//RtmprstflM/file13fbe440398d6.tsv, and saved nodeset 'Lawyers' to file: lazega_nodes.tsv.
file.exists(tmp_net)
#> [1] TRUE
unlink(tmp_net)Load back from file:
Delete individual structures:
th_delete(lazega)
#> Structure 'lazega' removed.
th_delete(lazega_nodeset)
#> Structure 'lazega_nodeset' removed.
th_i()
#> No structures stored in the current session.Or delete everything:
Stop Threadle:
sessionInfo()
#> R version 4.5.2 (2025-10-31)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sequoia 15.7.3
#>
#> Matrix products: default
#> BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#>
#> time zone: Europe/Stockholm
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] threadleR_0.4.3
#>
#> loaded via a namespace (and not attached):
#> [1] digest_0.6.37 R6_2.6.1 fastmap_1.2.0 xfun_0.52
#> [5] cachem_1.1.0 knitr_1.50 htmltools_0.5.8.1 rmarkdown_2.29
#> [9] lifecycle_1.0.4 ps_1.9.1 cli_3.6.5 processx_3.8.6
#> [13] sass_0.4.10 jquerylib_0.1.4 compiler_4.5.2 rstudioapi_0.17.1
#> [17] tools_4.5.2 evaluate_1.0.3 bslib_0.9.0 yaml_2.3.10
#> [21] rlang_1.1.6 jsonlite_2.0.0