From e7603b9d2677c14a1f2e5b3db0625da8decab921 Mon Sep 17 00:00:00 2001 From: tdelcey_w Date: Wed, 11 Feb 2026 21:34:21 +0100 Subject: [PATCH 1/2] update v 1.0.1 dev developement --- DESCRIPTION | 34 +- NAMESPACE | 1 - NEWS.md | 4 +- R/Authors_stagflation.R | 8 +- R/Edges_coupling.R | 4 +- R/Nodes_coupling.R | 12 +- R/Nodes_stagflation.R | 16 +- R/Ref_stagflation.R | 12 +- R/add_clusters.R | 272 +++++--- R/add_node_roles.R | 15 +- R/build_dynamic_networks.R | 832 ++++++++++------------- R/build_dynamic_networks2.R | 536 --------------- R/color_networks.R | 15 +- R/dynamic_network_cooccurrence.R | 22 +- R/extract_tfidf.R | 19 +- R/intertemporal_cluster_naming.R | 36 +- R/launch_network_app.R | 32 +- R/layout_networks.R | 17 +- R/merge_dynamic_clusters.R | 17 +- R/name_clusters.R | 23 +- R/networks_to_alluv.R | 23 +- R/plot_networks.R | 4 +- README.Rmd | 84 ++- README.html | 683 +++++++++++++++++++ README.md | 113 +-- _pkgdown.yml | 13 +- data/Authors_stagflation.rda | Bin 2348 -> 2221 bytes data/Nodes_coupling.rda | Bin 7430 -> 8264 bytes data/Nodes_stagflation.rda | Bin 21114 -> 24872 bytes data/Ref_stagflation.rda | Bin 84718 -> 97213 bytes inst/data-raw/creating_network_data.R | 12 +- man/Authors_stagflation.Rd | 8 +- man/Edges_coupling.Rd | 4 +- man/Nodes_coupling.Rd | 12 +- man/Nodes_stagflation.Rd | 16 +- man/Ref_stagflation.Rd | 12 +- man/add_clusters.Rd | 16 +- man/add_node_roles.Rd | 14 +- man/build_dynamic_networks.Rd | 224 +++--- man/build_dynamic_networks2.Rd | 160 ----- man/build_network.Rd | 49 ++ man/color_networks.Rd | 14 +- man/dynamic_network_cooccurrence.Rd | 14 +- man/extract_tfidf.Rd | 18 +- man/intertemporal_cluster_naming.Rd | 16 +- man/launch_network_app.Rd | 32 +- man/layout_networks.Rd | 16 +- man/merge_dynamic_clusters.Rd | 16 +- man/name_clusters.Rd | 22 +- man/networkflow-package.Rd | 3 +- man/networks_to_alluv.Rd | 22 +- vignettes/.gitignore | 3 + vignettes/exploring_dynamic_networks.Rmd | 142 ---- vignettes/networkflow_presentation.Rmd | 627 +++++++++++++++++ vignettes/workflow-network.Rmd | 137 ---- 55 files changed, 2373 insertions(+), 2083 deletions(-) delete mode 100644 R/build_dynamic_networks2.R create mode 100644 README.html delete mode 100644 man/build_dynamic_networks2.Rd create mode 100644 man/build_network.Rd delete mode 100644 vignettes/exploring_dynamic_networks.Rmd create mode 100644 vignettes/networkflow_presentation.Rmd delete mode 100644 vignettes/workflow-network.Rmd diff --git a/DESCRIPTION b/DESCRIPTION index 914302b..531c7fe 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,31 +1,23 @@ Package: networkflow Title: Functions For A Workflow To Manipulate Networks -Version: 0.1.0 +Version: 1.0.0 Date: 2022-11-25 Authors@R: c( person("Aurélien", "Goutsmedt", , "agoutsmedt@gmail.com", role = c("cre", "aut"), comment = c(ORCID = "0000-0002-3788-7237")), person("Alexandre", "Truc", , "alexandre.truc77@gmail.com", role = c("aut"), - comment = c(ORCID = "0000-0002-1328-7819")) + comment = c(ORCID = "0000-0002-1328-7819")), + person("Thomas", "Delcey", role = c("aut"), comment = c(ORCID = "0000-0003-0546-1474")) ) -Author: Aurélien Goutsmedt and Alexandre Truc. +Author: Aurelien Goutsmedt, Alexandre Truc and Thomas Delcey. Maintainer: Aurélien Goutsmedt -Description: This package proposes a series of function to make it easier - and quicker to work on networks. It mainly targets working on - bibliometric networks (see the - [biblionetwork](https://github.com/agoutsmedt/biblionetwork) package - for creating such networks). This package heavily relies on - [igraph](https://igraph.org/r/) and - [tidygraph](https://tidygraph.data-imaginist.com/index.html), and aims - at producing ready-made networks for projecting them using - [ggraph](https://ggraph.data-imaginist.com/). This package does not - invent nothing new, properly speaking, but it allows the users to - follow more quickly and easily the main steps of network manipulation, - from creating the graph to projecting it. It is inspired by what could - be done with [GEPHI](https://gephi.org/): the package allows the use - of the Leiden community detection algorithm, as well as of the Force - Atlas 2 layout, both being unavailable in igraph (and so in - tidygraph). +Description: Provides a workflow to build, analyze, and visualize projected + networks from tabular data. The package supports dynamic analysis across + time windows, including cluster detection and cross-period cluster matching. + It also covers network construction, interpretation, static plotting, and + interactive exploration through a 'shiny' app. Although designed for + projected networks (e.g., article -> reference), it can be used more + generally with 'tbl_graph' objects. License: MIT + file LICENSE URL: https://github.com/agoutsmedt/networkflow, https://agoutsmedt.github.io/networkflow/ @@ -71,6 +63,4 @@ Remotes: Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 - - +RoxygenNote: 7.3.3 diff --git a/NAMESPACE b/NAMESPACE index 42329d3..f90e0ac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,7 +4,6 @@ export("%>%") export(add_clusters) export(add_node_roles) export(build_dynamic_networks) -export(build_dynamic_networks2) export(build_network) export(color_alluvial) export(color_networks) diff --git a/NEWS.md b/NEWS.md index a15a654..a93f07f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,6 @@ -# networkflow 0.1.0 (Development) +# networkflow 1.0.0 + +First stable release. Deprecated and new functions: diff --git a/R/Authors_stagflation.R b/R/Authors_stagflation.R index d4f76e8..ac0f93a 100644 --- a/R/Authors_stagflation.R +++ b/R/Authors_stagflation.R @@ -4,11 +4,11 @@ #' the US stagflation and their authors (`Nodes_stagflation` just takes the first author; #' here is the complete list of authors per document). #' -#' @format A data frame with 558 rows and 7 variables: +#' @format A data frame with 231 rows and 3 variables: #' \describe{ -#' \item{ItemID_Ref}{Identifier of the document published by the author} -#' \item{Author}{Author of the document} -#' \item{Order}{Use this as a label for nodes} +#' \item{source_id}{Identifier of the document published by the author} +#' \item{author_name}{Author of the document} +#' \item{author_order}{Author order in the document author list} #' } #' @source Goutsmedt A. (2020) “From Stagflation to the Great Inflation: Explaining the 1970s US Economic #' Situation”. Revue d’Economie Politique, Forthcoming 2021. diff --git a/R/Edges_coupling.R b/R/Edges_coupling.R index fbeab5c..48ec4ae 100644 --- a/R/Edges_coupling.R +++ b/R/Edges_coupling.R @@ -1,10 +1,10 @@ #' Edges For Bibliographic Coupling Network Of Articles and Books Explaining the 1970s US Stagflation. #' #' A dataset containing the edges of the bibliographic coupling network of articles and books on stagflation. -#' Built by using [Ref_stagflation]: `biblionetwork::biblio_coupling(Ref_stagflation,"Citing_ItemID_Ref","ItemID_Ref")`. +#' Built by using [Ref_stagflation]: `biblionetwork::biblio_coupling(Ref_stagflation,"source_id","target_id")`. #' Could be used with [Nodes_coupling] to create a network with tidygraph. #' -#' @format A data frame with 154 rows and 6 variables: +#' @format A data frame with 2593 rows and 5 variables: #' \describe{ #' \item{from}{Identifier of the Source document on stagflation, in character format} #' \item{to}{Identifier of the Target document on stagflation, in character format} diff --git a/R/Nodes_coupling.R b/R/Nodes_coupling.R index ae4588e..16b3c6e 100644 --- a/R/Nodes_coupling.R +++ b/R/Nodes_coupling.R @@ -7,12 +7,12 @@ #' #' @format A data frame with 154 rows and 6 variables: #' \describe{ -#' \item{ItemID_Ref}{Identifier of the document on stagflation, in character format} -#' \item{Author}{Author of the document on stagflation} -#' \item{Author_date}{Use this as a label for nodes} -#' \item{Year}{Year of publication of the document} -#' \item{Title}{Title of the document} -#' \item{Journal}{Journal of publication of the document (if an article)} +#' \item{source_id}{Identifier of the document on stagflation, in character format} +#' \item{source_author}{Author of the document on stagflation} +#' \item{source_label}{Use this as a label for nodes} +#' \item{source_year}{Year of publication of the document} +#' \item{source_title}{Title of the document} +#' \item{source_journal}{Journal of publication of the document (if an article)} #' } #' @source Created from `Nodes_stagflation.rda` diff --git a/R/Nodes_stagflation.R b/R/Nodes_stagflation.R index 7e34f65..da86937 100644 --- a/R/Nodes_stagflation.R +++ b/R/Nodes_stagflation.R @@ -4,15 +4,15 @@ #' what happened in the US economy in the 1970s, as well as all the articles and books #' cited at least twice by the first set of articles and books (on the stagflation). #' -#' @format A data frame with 558 rows and 7 variables: +#' @format A data frame with 654 rows and 7 variables: #' \describe{ -#' \item{ItemID_Ref}{Identifier of the document} -#' \item{Author}{Author of the document} -#' \item{Author_date}{Use this as a label for nodes} -#' \item{Year}{Year of publication of the document} -#' \item{Title}{Title of the document} -#' \item{Journal}{Journal of publication of the document (if an article)} -#' \item{Type}{If "Stagflation", the document is listed as an explanation of the US stagflation. +#' \item{source_id}{Identifier of the document} +#' \item{source_author}{Author of the document} +#' \item{source_label}{Use this as a label for nodes} +#' \item{source_year}{Year of publication of the document} +#' \item{source_title}{Title of the document} +#' \item{source_journal}{Journal of publication of the document (if an article)} +#' \item{source_type}{If "Stagflation", the document is listed as an explanation of the US stagflation. #' If "Non-Stagflation", the document is cited by a document explaining the stagflation} #' } #' @source Goutsmedt A. (2020) “From Stagflation to the Great Inflation: Explaining the 1970s US Economic diff --git a/R/Ref_stagflation.R b/R/Ref_stagflation.R index 555a272..82e342d 100644 --- a/R/Ref_stagflation.R +++ b/R/Ref_stagflation.R @@ -6,12 +6,12 @@ #' #' @format A data frame with 4416 rows and 6 variables: #' \describe{ -#' \item{Citing_ItemID_Ref}{Identifier of the citing document} -#' \item{ItemID_Ref}{Identifier of the cited document} -#' \item{Author}{Author of the cited document} -#' \item{Year}{Year of publication of the cited document} -#' \item{Title}{Title of the cited document} -#' \item{Journal}{Journal of publication of the cited document (if an article)} +#' \item{source_id}{Identifier of the citing document} +#' \item{target_id}{Identifier of the cited document} +#' \item{target_author}{Author of the cited document} +#' \item{target_year}{Year of publication of the cited document} +#' \item{target_title}{Title of the cited document} +#' \item{target_journal}{Journal of publication of the cited document (if an article)} #' } #' @source Goutsmedt A. (2020) “From Stagflation to the Great Inflation: Explaining the 1970s US Economic #' Situation”. Revue d’Economie Politique, Forthcoming 2021. diff --git a/R/add_clusters.R b/R/add_clusters.R index 0d473cb..8334f2d 100644 --- a/R/add_clusters.R +++ b/R/add_clusters.R @@ -1,16 +1,23 @@ -add_clusters <- function(graphs, - weights = NULL, - clustering_method = c("leiden", "louvain", "fast_greedy", "infomap", "walktrap"), - objective_function = c("modularity", "CPM"), #leiden - resolution = 1, #leiden - n_iterations = 1000, #leiden - n_groups = NULL, #fast_greedy & walktrap - node_weights = NULL, #infomap & Leiden - trials = 10, #infomap - steps = 4, #walktrap - verbose = TRUE, - seed = NA - ){ +add_clusters <- function( + graphs, + weights = NULL, + clustering_method = c( + "leiden", + "louvain", + "fast_greedy", + "infomap", + "walktrap" + ), + objective_function = c("modularity", "CPM"), #leiden + resolution = 1, #leiden + n_iterations = 1000, #leiden + n_groups = NULL, #fast_greedy & walktrap + node_weights = NULL, #infomap & Leiden + trials = 10, #infomap + steps = 4, #walktrap + verbose = TRUE, + seed = NA +) { #' Detect and Add Clusters to Graphs #' #' @description @@ -93,7 +100,7 @@ add_clusters <- function(graphs, #' for the edges, called `cluster_leiden_from`, `cluster_leiden_to` and `cluster_leiden`. #' @details The function also #' automatically calculates the percentage of total nodes that are gathered in each - #' cluster, in the column `size_com`. + #' cluster, in the column `size_cluster_{clustering_method}`. #' @details To make plotting easier later, a zero is put before one-digit cluster identifier #' (cluster 5 becomes "05"; cluster 10 becomes "10"). Attributing a cluster identifier to edges #' allow for giving edges the same color of the nodes they are connecting together if the two nodes have the same color, @@ -106,18 +113,16 @@ add_clusters <- function(graphs, #' @examples #' library(networkflow) #' - #' nodes <- Nodes_stagflation |> - #' dplyr::rename(ID_Art = ItemID_Ref) |> - #' dplyr::filter(Type == "Stagflation") + #' nodes <- networkflow::Nodes_stagflation |> + #' dplyr::filter(source_type == "Stagflation") #' - #' references <- Ref_stagflation |> - #' dplyr::rename(ID_Art = Citing_ItemID_Ref) + #' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, - #' source_id = "ID_Art", - #' target_id = "ItemID_Ref", - #' time_variable = "Year", + #' source_id = "source_id", + #' target_id = "target_id", + #' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -137,92 +142,116 @@ add_clusters <- function(graphs, #' @export #' - if(length(clustering_method) > 1){ - cli::cli_abort(c("You did not choose any clustering method! You have the choice between: ", - "*" = "\"leiden\";", - "*" = "\"louvain\";", - "*" = "\"fast_greedy\";", - "*" = "\"infomap\";", - "*" = "\"walktrap\".")) + if (length(clustering_method) > 1) { + cli::cli_abort(c( + "You did not choose any clustering method! You have the choice between: ", + "*" = "\"leiden\";", + "*" = "\"louvain\";", + "*" = "\"fast_greedy\";", + "*" = "\"infomap\";", + "*" = "\"walktrap\"." + )) } - if(! clustering_method %in% c("leiden", "louvain", "fast_greedy", "infomap", "walktrap")){ - cli::cli_abort("The method you have chosen is not implemented within the function.") + if ( + !clustering_method %in% + c("leiden", "louvain", "fast_greedy", "infomap", "walktrap") + ) { + cli::cli_abort( + "The method you have chosen is not implemented within the function." + ) } - if(length(objective_function) > 1 & clustering_method == "leiden"){ - cli::cli_abort(c("You did not choose any objective function for the Leiden algorithm. You have the choice between: ", - "*" = "\"CPM\";", - "*" = "\"modularity\".")) - if(clustering_method %in% c("leiden", "louvain", "fast_greedy", "infomap", "walktrap")){ - cli::cli_alert_info("You are using the {.emph {.strong {clustering_method}}} clustering method.") + if (length(objective_function) > 1 & clustering_method == "leiden") { + cli::cli_abort(c( + "You did not choose any objective function for the Leiden algorithm. You have the choice between: ", + "*" = "\"CPM\";", + "*" = "\"modularity\"." + )) + if ( + clustering_method %in% + c("leiden", "louvain", "fast_greedy", "infomap", "walktrap") + ) { + cli::cli_alert_info( + "You are using the {.emph {.strong {clustering_method}}} clustering method." + ) + } } - } - - if(!is.na(seed)){ + if (!is.na(seed)) { set.seed(seed) } - if(inherits(graphs, "list")){ + if (inherits(graphs, "list")) { list <- TRUE - cluster_list_graph <- lapply(graphs, function(graph) detect_cluster(graph, - weights = weights, - clustering_method = clustering_method, - objective_function = objective_function, - resolution = resolution, - n_iterations = n_iterations, - n_groups = n_groups, - node_weights = node_weights, - trials = trials, - steps = steps, - list = list, - verbose = verbose)) + cluster_list_graph <- lapply(graphs, function(graph) { + detect_cluster( + graph, + weights = weights, + clustering_method = clustering_method, + objective_function = objective_function, + resolution = resolution, + n_iterations = n_iterations, + n_groups = n_groups, + node_weights = node_weights, + trials = trials, + steps = steps, + list = list, + verbose = verbose + ) + }) return(cluster_list_graph) } - if(inherits(graphs, "tbl_graph")){ + if (inherits(graphs, "tbl_graph")) { list <- FALSE - cluster_graph <- detect_cluster(graphs, - weights = weights, - clustering_method = clustering_method, - objective_function = objective_function, - resolution = resolution, - n_iterations = n_iterations, - n_groups = n_groups, - node_weights = node_weights, - trials = trials, - steps = steps, - list = list, - verbose = verbose) + cluster_graph <- detect_cluster( + graphs, + weights = weights, + clustering_method = clustering_method, + objective_function = objective_function, + resolution = resolution, + n_iterations = n_iterations, + n_groups = n_groups, + node_weights = node_weights, + trials = trials, + steps = steps, + list = list, + verbose = verbose + ) return(cluster_graph) } } # function in the tidygraph style to import Leiden community detection -group_leiden <- function(graph = graph, - objective_function = objective_function, - weights = weights, - resolution = resolution, - n_iterations = n_iterations, - node_weights = node_weights){ - igraph::cluster_leiden(graph, - resolution_parameter = resolution, - objective_function = objective_function, - weights = weights, - n_iterations = n_iterations, - vertex_weights = node_weights) %>% +group_leiden <- function( + graph = graph, + objective_function = objective_function, + weights = weights, + resolution = resolution, + n_iterations = n_iterations, + node_weights = node_weights +) { + igraph::cluster_leiden( + graph, + resolution_parameter = resolution, + objective_function = objective_function, + weights = weights, + n_iterations = n_iterations, + vertex_weights = node_weights + ) %>% igraph::membership() } # extracting the appropriate clustering function depending on the method chosen -extract_clustering_method <- function(clustering_method = clustering_method){ - . <- objective_function <- functions <- n_groups <- weights <- resolution <- n_iterations <- node_weights <- trials <- steps <- method <- graph <- NULL +extract_clustering_method <- function(clustering_method = clustering_method) { + . <- objective_function <- functions <- n_groups <- weights <- resolution <- n_iterations <- node_weights <- trials <- steps <- method <- graph <- NULL function_table <- dplyr::tribble( - ~ method, ~functions, - "leiden", rlang::expr(group_leiden(graph, objective_function = objective_function, weights = weights, resolution = resolution, n_iterations = n_iterations, node_weights = node_weights)), - "louvain", rlang::expr(tidygraph::group_louvain(weights = weights)), - "fast_greedy", rlang::expr(tidygraph::group_fast_greedy(weights = weights, n_groups = n_groups)), - "infomap", rlang::expr(tidygraph::group_infomap(weights = weights, node_weights = node_weights, trials = trials)), - "walktrap", rlang::expr(tidygraph::group_walktrap(weights = weights, steps = steps, n_groups = n_groups))) + ~method , ~functions , + "leiden" , rlang::expr(group_leiden(graph, objective_function = objective_function, weights = weights, resolution = resolution, n_iterations = n_iterations, node_weights = node_weights)) , + "louvain" , rlang::expr(tidygraph::group_louvain(weights = weights)) , + "fast_greedy" , rlang::expr(tidygraph::group_fast_greedy(weights = weights, n_groups = n_groups)) , + "infomap" , rlang::expr(tidygraph::group_infomap(weights = weights, node_weights = node_weights, trials = trials)) , + "walktrap" , rlang::expr(tidygraph::group_walktrap(weights = weights, steps = steps, n_groups = n_groups)) + ) fun <- function_table %>% dplyr::filter(method == clustering_method) %>% dplyr::pull(functions) %>% @@ -232,21 +261,23 @@ extract_clustering_method <- function(clustering_method = clustering_method){ } # function to detect the clusters on one graph -detect_cluster <- function(graph, - weights = weights, - clustering_method = clustering_method, - objective_function = objective_function, - resolution = resolution, - n_iterations = n_iterations, - n_groups = n_groups, - node_weights = node_weights, - trials = trials, - steps = steps, - list = list, - verbose = verbose){ +detect_cluster <- function( + graph, + weights = weights, + clustering_method = clustering_method, + objective_function = objective_function, + resolution = resolution, + n_iterations = n_iterations, + n_groups = n_groups, + node_weights = node_weights, + trials = trials, + steps = steps, + list = list, + verbose = verbose +) { . <- from <- to <- NULL - if(clustering_method %in% c("infomap", "leiden") & !is.null(node_weights)){ + if (clustering_method %in% c("infomap", "leiden") & !is.null(node_weights)) { node_weights <- graph %N>% dplyr::pull(node_weights) } @@ -258,18 +289,27 @@ detect_cluster <- function(graph, size_col <- paste0("size_cluster_", clustering_method) graph <- graph %N>% - dplyr::mutate({{ cluster_col }} := eval(fun), - {{ cluster_col }} := sprintf("%02d", eval(cluster_col)), - {{ size_col }} := dplyr::n()) %>% + dplyr::mutate( + {{ cluster_col }} := eval(fun), + {{ cluster_col }} := sprintf("%02d", eval(cluster_col)), + {{ size_col }} := dplyr::n() + ) %>% dplyr::group_by(dplyr::across({{ cluster_col }})) %>% - dplyr::mutate({{ size_col }} := dplyr::n()/eval(rlang::ensym(size_col))) %>% + dplyr::mutate( + {{ size_col }} := dplyr::n() / eval(rlang::ensym(size_col)) + ) %>% dplyr::ungroup() %E>% - dplyr::mutate("{ cluster_col }_from" := .N()[[cluster_col]][from], - "{ cluster_col }_to" := .N()[[cluster_col]][to], - {{ cluster_col }} := ifelse(eval(rlang::ensym(cluster_col_from)) == eval(rlang::ensym(cluster_col_to)), - eval(rlang::ensym(cluster_col_from)), - "00")) - if(verbose == TRUE){ + dplyr::mutate( + "{ cluster_col }_from" := .N()[[cluster_col]][from], + "{ cluster_col }_to" := .N()[[cluster_col]][to], + {{ cluster_col }} := ifelse( + eval(rlang::ensym(cluster_col_from)) == + eval(rlang::ensym(cluster_col_to)), + eval(rlang::ensym(cluster_col_from)), + "00" + ) + ) + if (verbose == TRUE) { nb_clusters <- graph %N>% dplyr::pull(cluster_col) %>% unique %>% @@ -278,10 +318,18 @@ detect_cluster <- function(graph, max_size <- graph %N>% dplyr::pull(size_col) %>% max() %>% - round(3) * 100 + round(3) * + 100 - if(list == TRUE) cli::cli_h1("Cluster detection for the {.val {graph %N>% as.data.frame() %>% dplyr::pull(time_window) %>% unique()}} period") - cli::cli_alert_info("The {.emph {clustering_method}} method detected {.val {nb_clusters}} clusters. The biggest cluster represents {.val {max_size}%} of the network.") + if (list == TRUE) { + cli::cli_h1( + "Cluster detection for the {.val {graph %N>% as.data.frame() %>% dplyr::pull(time_window) %>% unique()}} period" + ) + } + cli::cli_alert_info( + "The {.emph {clustering_method}} method detected {.val {nb_clusters}} clusters. The biggest cluster represents {.val {max_size}%} of the network." + ) } return(graph) } + diff --git a/R/add_node_roles.R b/R/add_node_roles.R index 93d64e4..72a7c66 100644 --- a/R/add_node_roles.R +++ b/R/add_node_roles.R @@ -36,18 +36,16 @@ #' @examples #' library(networkflow) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -274,3 +272,4 @@ add_node_roles_one <- function( dplyr::left_join(roles_tbl, by = ".node_id") %>% dplyr::select(-.node_id) } + diff --git a/R/build_dynamic_networks.R b/R/build_dynamic_networks.R index c7056d5..627ede4 100644 --- a/R/build_dynamic_networks.R +++ b/R/build_dynamic_networks.R @@ -1,346 +1,151 @@ -#' Creating One or Multiple Networks from a List of Nodes and Directed Edges +#' Build One or Multiple Networks from Bipartite Links #' #' @description #' `r lifecycle::badge("experimental")` #' -#' `build_network()` creates a network from a table of nodes and its -#' directed edges. That is a special case of the more general `build_dynamic_networks()`. -#' This function creates one or several tibble graphs (built with -#' [tidygraph](https://tidygraph.data-imaginist.com/)) from a table of nodes and its -#' directed edges. For instance, for bibliometric networks, you can give a list of -#' articles and the list of the references these articles cite. You can use it to -#' build a single network or multiple networks over different time windows. -#' -#' @param nodes -#' The table with all the nodes and their metadata. For instance, if your nodes are -#' articles, this table is likely to contain the year of publication, the name of the authors, -#' the title of the article, etc... The table must have one row per node. -#' -#' @param directed_edges -#' The table with of all the elements to which your nodes are connected. If your nodes are -#' articles, the `directed_edges` table can contain the list of the references cited -#' by these articles, the authors that have written these articles, or the affiliations -#' of the authors of these articles. -#' -#' @param source_id -#' The quoted name of the column with the unique identifier of each node. For instance, -#' for a bibliographic coupling network, the id of your citing documents. It corresponds -#' to the `source` argument of [biblionetwork](https://agoutsmedt.github.io/biblionetwork/) -#' functions. -#' -#' @param target_id -#' The quoted name of the column with the unique identifier of each element connected to the node (for -#' instance, the identifier of the reference cited by your node if the node is an article). -#' It corresponds to the `ref` argument of -#' [biblionetwork](https://agoutsmedt.github.io/biblionetwork/) functions. -#' -#' @param time_variable -#' The column with the temporal variable you want to use to build your windows for the -#' succession of networks. By default, `time_variable` is `NULL` and the function -#' will only build one network without taking into account any temporal variable. -#' -#' @param time_window -#' The length of your network relatively of the unity of the `time_variable` column. If you -#' use a variable in years as `time_variable` and you set `time_window` at 5, the function -#' will build network on five year windows. By default, `time_window` is `NULL` and the -#' function will only build one network. -#' -#' @param overlapping_window -#' Set to `FALSE` by default. If set to `TRUE`, and if `time_variable` and `time_window` not -#' `NULL`, the function will create a succession of networks for moving time windows. The windows are -#' moving one unit per one unit of the `time_variable`. For instance, for years, if `time_window` -#' set to 5, it creates networks for successive time windows like 1970-1974, 1971-1975, 1972-1976, etc. -#' -#' @param cooccurrence_method -#' Choose a cooccurrence method to build your indirect edges table. The function propose -#' three methods that depends on the [biblionetwork package](https://agoutsmedt.github.io/biblionetwork/) -#' and three methods that are implemented in it: -#' -#' - the coupling angle measure (see [biblionetwork::biblio_coupling()] for documentation); -#' - the coupling strength measure ([biblionetwork::coupling_strength()]); -#' - the coupling similarity measure ([biblionetwork:: coupling_similarity()]). -#' -#' @param backbone_method Method used to extract the network backbone. Choose between: +#' `build_dynamic_networks()` builds one or several `tbl_graph` networks from a +#' node table (`source_id`) and a bipartite link table (`source_id` -> `target_id`). `build_network()` is a wrapper for a single network. +#' +#' It supports two backbone extraction methods: +#' - structured filtering using coupling/cooccurrence measures from +#' [biblionetwork](https://agoutsmedt.github.io/biblionetwork/); +#' - statistical filtering using null models from +#' [backbone](https://github.com/zpneal/backbone) \insertCite{neal2022}{networkflow}. +#' +#' The function can build a single network or multiple networks across time windows. +#' +#' @param nodes Table of nodes and their metadata. One row per node. For example, a table +#' of articles with identifiers, authors, publication year, etc. +#' +#' @param directed_edges Table of bipartite links between `source_id` nodes and +#' `target_id` entities (e.g., article -> reference, author -> paper). +#' +#' @param source_id Quoted name of the source-side node identifier. +#' +#' @param target_id Quoted name of the target-side identifier linked to each source node. +#' +#' @param time_variable Optional name of the column with a temporal variable (e.g., publication year). +#' +#' @param time_window Optional size of the time window (in units of `time_variable`) to construct temporal networks. +#' +#' @param projection_method method used to extract the network backbone. Choose between: #' - `"structured"`: uses cooccurrence measures from the [biblionetwork](https://agoutsmedt.github.io/biblionetwork/) package; -#' - `"statistical"`: uses statistical models from the [backbone](https://github.com/djmurphy533/backbone) package. +#' - `"statistical"`: uses statistical models from the [backbone](https://github.com/zpneal/backbone) package. +#' Defaults to `"structured"`. The `"statistical"` method can be computationally slow on large networks. + #' -#' @param statistical_method For `backbone_method = "statistical"`, select the null model: one of -#' `"sdsm"`, `"fdsm"`, `"fixedfill"`, `"fixedfrow"`, `"fixedcol"`. +#' @param model Statistical null model from [backbone](https://github.com/zpneal/backbone): +#' one of `"sdsm"`, `"fdsm"`, `"fixedfill"`, `"fixedrow"`, `"fixedcol"`. +#' Required if `projection_method = "statistical"`. #' -#' @param alpha Significance threshold for statistical backbone extraction. Required if -#' `backbone_method = "statistical"`. #' -#' @param edges_threshold -#' Threshold value for building your edges. With a higher threshold, only the stronger links -#' will be kept. See the [biblionetwork package](https://agoutsmedt.github.io/biblionetwork/) -#' documentation and the `cooccurrence_method` parameter. +#' @param alpha Significance threshold for statistical backbone filtering. Required if +#' `projection_method = "statistical"`. Lower values keep fewer edges. #' -#' @param compute_size -#' Set to `FALSE` by default. If `TRUE`, the function uses the `directed_edges` data -#' to calculate how many directed edges a node receives (as a target). If `directed_edges` -#' is a table of direct citations, the functions calculates the number of time a node -#' is cited by the other nodes. You need to have the `target_id` in the `nodes` table -#' to make the link with the targetted nodes in the `directed_edges` table. +#' @param cooccurrence_method For `projection_method = "structured"`, choose the coupling method: +#' - `"coupling_angle"` +#' - `"coupling_strength"`; +#' - `"coupling_similarity"`. #' -#' @param keep_singleton -#' Set to `FALSE` by default. If `TRUE`, the function removes the nodes that have no -#' undirected edges, i.e. no cooccurrence with any other nodes. In graphical terms, -#' these nodes are alone in the network, with no link with other nodes. +#' @param edges_threshold Threshold used to filter weak edges in structured mode. #' -#' @param filter_components -#' Set to `TRUE` if you want to run `networkflow::filter_components()` -#' to filter the components of the network(s) and keep only the biggest component(s). If -#' you don't change the defaults parameters of `networkflow::filter_components()`, -#' it will keep only the main component. +#' @param overlapping_window Logical. If `TRUE`, builds networks using rolling time windows. #' -#' @param ... -#' Additional arguments from `networkflow::filter_components()`. +#' @param compute_size Logical. If `TRUE`, computes the number of incoming edges per node (e.g., citation count). #' -#' @param verbose -#' Set to `FALSE` if you don't want the function to display different sort of information. +#' @param keep_singleton Logical. If `FALSE`, removes nodes with no edges in the final network. #' -#' @details `build_network()` has been added for convenience but it is just -#' a special case of the more general `build_dynamic_networks()`, with +#' @param filter_components Logical. If `TRUE`, keeps only the main component(s) using `networkflow::filter_components()`. #' +#' @param ... Additional arguments passed to `filter_components()`. #' +#' @param backbone_args Optional list of additional arguments passed to the +#' backbone extraction call. If `backbone_args` includes `alpha` or `model`, +#' those values override function arguments. #' -#' @return If `time_window` is `NULL`, the function computes only -#' one network and return a tidygraph object built with [tbl_graph()][tidygraph::tbl_graph()]. -#' If `time_variable` and `time_window` are not `NULL`, the function returns a list -#' of tidygraph networks, for each time window. +#' @param verbose Logical. If `TRUE`, displays progress messages. +#' +#' @details +#' The function uses bipartite links (`source_id` -> `target_id`) to produce +#' source-side networks. +#' +#' If `time_variable` and `time_window` are provided, it builds one network per +#' time window (rolling or non-overlapping). Otherwise it builds a single network. +#' +#' `projection_method = "structured"` applies coupling/cooccurrence filtering. +#' `projection_method = "statistical"` applies a statistical backbone model. #' #' @examples #' library(networkflow) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' -#' temporal_networks <- build_dynamic_networks(nodes = nodes, +#' # Structured backbone (cooccurrence) +#' net_structured <- build_dynamic_networks( +#' nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", +#' time_window = 20, +#' projection_method = "structured", #' cooccurrence_method = "coupling_similarity", +#' edges_threshold = 1 +#' ) +#' +#' # Statistical backbone (backbone package) +#' net_statistical <- build_dynamic_networks( +#' nodes = nodes, +#' directed_edges = references, +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' time_window = 20, -#' edges_threshold = 1, -#' overlapping_window = TRUE) +#' projection_method = "statistical", +#' model = "sdsm", +#' alpha = 0.05, +#' backbone_args = list(mtc = "holm") +#' ) #' -#' temporal_networks[[1]] +#' @return +#' - A single tidygraph object if `time_window` is `NULL`; +#' - A list of tidygraph objects (one per time window) otherwise. +#' +#' @seealso [biblionetwork::biblio_coupling()], [backbone::backbone()] +#' +#' @references +#' \insertAllCited{} #' #' @export -build_dynamic_networks <- function(nodes, - directed_edges, - source_id, - target_id, - time_variable = NULL, - time_window = NULL, - cooccurrence_method = c("coupling_angle","coupling_strength","coupling_similarity"), - overlapping_window = FALSE, - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ..., - verbose = TRUE) -{ - size <- node_size <- N <- method <- NULL - - - # Making sure the table is a datatable - nodes <- data.table::data.table(nodes) - directed_edges <- data.table::data.table(directed_edges) - cooccurrence_methods <- c("coupling_angle","coupling_strength","coupling_similarity") - - # Checking various problems: lacking method, - if(length(cooccurrence_method) > 1){ - cli::cli_abort(c( - "You did not choose any method for cooccurrence computation. You have to choose between: ", - "*" = "\"coupling_angle\";", - "*" = "\"coupling_strength\";", - "*" = "\"coupling_similarity\".")) - } - if(!cooccurrence_method %in% cooccurrence_methods){ - cli::cli_abort(c( - "You did not choose an existing method for cooccurrence computation. You have to choose between: ", - "*" = "\"coupling_angle\";", - "*" = "\"coupling_strength\";", - "*" = "\"coupling_similarity\".")) - } - if(nodes[, .N, source_id, env = list(source_id=source_id)][N > 1, .N] > 0){ - cli::cli_alert_warning("Some identifiers in your column {.field {source_id}} in your nodes table are not unique. You need only one row per node.") - } - - if(! is.null(time_window) & is.null(time_variable)){ - cli::cli_abort("You cannot have a {.emph time_window} if you don't give any column with a temporal variable. - Put a column in {.emph time_variable} or remove the {.emph time_window}.") - } - - # giving information on the method - - if(verbose == TRUE){ - cli::cli_alert_info("The method use for co-occurence is the {.emph {cooccurrence_method}} method.") - cli::cli_alert_info("The edge threshold is: {.val {edges_threshold}}.") - if(keep_singleton == FALSE) cli::cli_alert_info("We remove the nodes that are alone with no edge. \n\n") - } - - # let's extract the information we need - Nodes_coupling <- data.table::copy(nodes) - Nodes_coupling[, source_id := as.character(source_id), - env = list(source_id = source_id)] - - if(is.null(time_variable)){ - time_variable <- "fake_column" - Nodes_coupling[, time_variable := 1, - env = list(time_variable = time_variable)] - } - - if(! target_id %in% colnames(Nodes_coupling) & compute_size == TRUE) - { - cli::cli_abort("You don't have the column {.field {target_id}} in your nodes table. Set {.emph compute_size} to {.val FALSE}.") - } - - if(compute_size == TRUE){ - Nodes_coupling[, target_id := as.character(target_id), - env = list(target_id = target_id)] - } - - Edges <- data.table::copy(directed_edges) - Edges <- Edges[, .SD, .SDcols = c(source_id, target_id)] - Edges[, c(source_id, target_id) := lapply(.SD, as.character), .SDcols = c(source_id, target_id)] - - ######################### Dynamics networks ********************* - - # Find the time_window - Nodes_coupling <- Nodes_coupling[order(time_variable), env = list(time_variable = time_variable)] - Nodes_coupling[, time_variable := as.integer(time_variable), - env = list(time_variable = time_variable)] - - first_year <- Nodes_coupling[, min(as.integer(time_variable)), - env = list(time_variable = time_variable)] - last_year <- Nodes_coupling[, max(as.integer(time_variable)), - env = list(time_variable = time_variable)] - - if(!is.null(time_window)){ - if(last_year - first_year + 1 < time_window){ - cli::cli_alert_warning("Your time window is larger than the number of distinct values of {.field {time_variable}}") - } - } - - if(is.null(time_window)){ - all_years <- first_year - time_window <- last_year - first_year + 1 - } else { - if(overlapping_window == TRUE){ - last_year <- last_year - time_window + 1 - all_years <- first_year:last_year - } else { - all_years <- seq(first_year, last_year, by = time_window) - if(all_years[length(all_years)] + (time_window - 1) > last_year){ - cli::cli_warn("Your last network is shorter than the other(s) because the cutting by time window does not give a round count. - The last time unity in your data is {.val {last_year}}, but the upper limit of your last time window is - {.val {all_years[length(all_years)] + (time_window - 1)}}.") - } - } - } - - # Prepare our list - tbl_coup_list <- list() - - for (Year in all_years) { - nodes_of_the_year <- Nodes_coupling[time_variable >= Year & time_variable < (Year + time_window), - env = list(time_variable = time_variable, Year = Year)] - - if(time_variable != "fake_column"){ - nodes_of_the_year[, time_window := paste0(Year, "-", Year + time_window - 1), - env = list(Year = Year)] - if(verbose == TRUE) cli::cli_h1("Creation of the network for the {.val {Year}}-{.val {Year + time_window - 1}} window.") - } else { - nodes_of_the_year <- nodes_of_the_year[, -c("fake_column")] - } - - edges_of_the_year <- Edges[source_id %in% nodes_of_the_year[, source_id], - env = list(source_id = source_id)] - - # size of nodes - if(compute_size == TRUE){ - nb_cit <- edges_of_the_year[source_id %in% nodes_of_the_year[, source_id], .N, target_id, - env = list(source_id = source_id, target_id = target_id)] - colnames(nb_cit)[colnames(nb_cit) == "N"] <- "node_size" - - if("node_size" %in% colnames(Nodes_coupling) == TRUE) - { - cli::cli_warn("You already have a column name {.field node_size}. The content of the column will be replaced.") - } - nodes_of_the_year <- data.table::merge.data.table(nodes_of_the_year, - nb_cit, - by = target_id, - all.x = TRUE) - nodes_of_the_year[is.na(node_size), node_size := 0] - } - - # coupling - biblio_functions <- data.table::data.table(biblio_function = c(rlang::expr(biblionetwork::biblio_coupling), - rlang::expr(biblionetwork::coupling_strength), - rlang::expr(biblionetwork::coupling_similarity)), - method = c("coupling_angle", - "coupling_strength", - "coupling_similarity")) - biblio_function <- biblio_functions[method == cooccurrence_method][["biblio_function"]][[1]] - edges_of_the_year <- rlang::expr((!!biblio_function)(dt = edges_of_the_year, - source = rlang::inject(source_id), - ref = rlang::inject(target_id), - weight_threshold = rlang::inject(edges_threshold))) %>% - eval() - - # remove nodes with no edges - if(keep_singleton==FALSE){ - nodes_of_the_year <- nodes_of_the_year[source_id %in% edges_of_the_year$from | source_id %in% edges_of_the_year$to, env=list(source_id=source_id)] - } - - # make tbl - if(length(all_years) == 1){ - tbl_coup_list <- tidygraph::tbl_graph(nodes = nodes_of_the_year, - edges = edges_of_the_year, - directed = FALSE, - node_key = source_id) - } else { - tbl_coup_list[[paste0(Year, "-", Year + time_window - 1)]] <- tidygraph::tbl_graph(nodes = nodes_of_the_year, - edges = edges_of_the_year, - directed = FALSE, - node_key = source_id) - } - } - if(filter_components == TRUE){ - tbl_coup_list <- filter_components(tbl_coup_list, ...) - } - return (tbl_coup_list) -} - -#' @rdname build_dynamic_networks -#' @export - -build_dynamic_networks2 <- function(nodes, - directed_edges, - source_id, - target_id, - time_variable = NULL, - time_window = NULL, - backbone_method = c("statistical", "structured"), - statistical_method = c("sdsm", "fdsm", "fixedfill", "fixedfrow", "fixedcol"), - alpha = NULL, - coupling_measure = c("coupling_angle", "coupling_strength", "coupling_similarity"), - edges_threshold = 1, - overlapping_window = FALSE, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ..., - verbose = TRUE) { +#' +build_dynamic_networks <- function( + nodes, + directed_edges, + source_id, + target_id, + time_variable = NULL, + time_window = NULL, + projection_method = c("structured", "statistical"), + model = c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol"), + alpha = NULL, + cooccurrence_method = c( + "coupling_angle", + "coupling_strength", + "coupling_similarity" + ), + edges_threshold = 1, + overlapping_window = FALSE, + compute_size = FALSE, + keep_singleton = FALSE, + filter_components = FALSE, + ..., + backbone_args = list(), + verbose = TRUE +) { size <- node_size <- N <- method <- NULL # Making sure the table is a datatable @@ -348,41 +153,31 @@ build_dynamic_networks2 <- function(nodes, directed_edges <- data.table::data.table(directed_edges) # Checking the methods - backbone_methods = c("statistical", "structured") - - coupling_measures <- c("coupling_angle", - "coupling_strength", - "coupling_similarity") + projection_methods <- c("structured", "statistical") - statistical_methods <- c("sdsm", "fdsm", "fixedfill", "fixedfrow", "fixedcol") + cooccurrence_methods <- c( + "coupling_angle", + "coupling_strength", + "coupling_similarity" + ) + statistical_methods <- c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol") - if (length(backbone_method) > 1) { - cli::cli_abort( - c( - "You did not choose any method for extracting the backbone. You have to choose between: ", - "*" = "\"statistical\";", - "*" = "\"structured\"." - ) - ) - } - - if (!backbone_method %in% backbone_methods) { - cli::cli_abort( - c( - "You did not choose any method for extracting the backbone. You have to choose between: ", - "*" = "\"statistical\";", - "*" = "\"structured\";" + if (length(projection_method) > 1) { + projection_method <- match.arg(projection_method, projection_methods) + if (verbose == TRUE && missing(projection_method)) { + cli::cli_alert_info( + "No projection_method provided. Defaulting to {.val {projection_method}}." ) - ) + } + } else { + projection_method <- match.arg(projection_method, projection_methods) } - # check various setting for the structured methods - - if (backbone_method == "structured") { - + # check various setting for the structured/statistical methods + if (projection_method == "structured") { # Checking various problems: lacking method, - if (length(coupling_measure) > 1) { + if (length(cooccurrence_method) > 1) { cli::cli_abort( c( "For structured backbone extraction, you have to choose a coupling measure among: ", @@ -393,7 +188,7 @@ build_dynamic_networks2 <- function(nodes, ) } - if (!coupling_measure %in% coupling_measures) { + if (!cooccurrence_method %in% cooccurrence_methods) { cli::cli_abort( c( "For structured backbone extraction, you have to choose a coupling measure among: ", @@ -403,49 +198,34 @@ build_dynamic_networks2 <- function(nodes, ) ) } - - } - - # check various setting for the statistical methods - if (backbone_method == "statistical") { - # check if a model is given - if (length(statistical_method) > 1) { + } else if (projection_method == "statistical") { + if (is.null(model) || length(model) > 1) { cli::cli_abort( c( "For statistical backbone extraction, you have to choose a model: ", "*" = "\"sdsm\";", "*" = "\"fdsm\";", "*" = "\"fixedfill\".", - "*" = "\"fixedfrow\".", + "*" = "\"fixedrow\".", "*" = "\"fixedcol\"." ) ) } - if (!statistical_method %in% statistical_methods) { - cli::cli_abort( - c( - "For statistical backbone extraction, you have to choose a model: ", - "*" = "\"sdsm\";", - "*" = "\"fdsm\";", - "*" = "\"fixedfill\".", - "*" = "\"fixedfrow\".", - "*" = "\"fixedcol\"." - ) - ) - } + model <- match.arg(model, statistical_methods) # check if alpha is given - if (is.null(alpha)) { + if (is.null(alpha) && is.null(backbone_args$alpha)) { cli::cli_abort( "For statistical backbone extraction, you have to choose a significance level alpha." ) } - } # warning if the source_id is not unique - if (nodes[, .N, source_id, env = list(source_id = source_id)][N > 1, .N] > 0) { + if ( + nodes[, .N, source_id, env = list(source_id = source_id)][N > 1, .N] > 0 + ) { cli::cli_alert_warning( "Some identifiers in your column {.field {source_id}} in your nodes table are not unique. You need only one row per node." ) @@ -461,56 +241,82 @@ build_dynamic_networks2 <- function(nodes, # VERBOSE if (verbose == TRUE) { - if (length(statistical_method > 0)) + if (!missing(projection_method)) { cli::cli_alert_info(paste( - "We extract the network backbone using the", - backbone_method, - "method." + "Backbone method selected:", + projection_method )) + } - if (keep_singleton == FALSE) - cli::cli_alert_info("Keep_singleton == FALSE: removing the nodes that are alone with no edge. \n\n") + if (keep_singleton == FALSE) { + cli::cli_alert_info( + "Keep_singleton == FALSE: removing the nodes that are alone with no edge. \n\n" + ) + } } - # CHECKING THE DATA # NODES nodes_coupling <- data.table::copy(nodes) - nodes_coupling[, source_id := as.character(source_id), env = list(source_id = source_id)] + nodes_coupling[, + source_id := as.character(source_id), + env = list(source_id = source_id) + ] if (is.null(time_variable)) { time_variable <- "fake_column" - nodes_coupling[, time_variable := 1, env = list(time_variable = time_variable)] + nodes_coupling[, + time_variable := 1, + env = list(time_variable = time_variable) + ] } - - if (!target_id %in% colnames(nodes_coupling) & - compute_size == TRUE) { + if ( + !target_id %in% colnames(nodes_coupling) & + compute_size == TRUE + ) { cli::cli_abort( "You don't have the column {.field {target_id}} in your nodes table. Set {.emph compute_size} to {.val FALSE}." ) } if (compute_size == TRUE) { - nodes_coupling[, target_id := as.character(target_id), env = list(target_id = target_id)] + nodes_coupling[, + target_id := as.character(target_id), + env = list(target_id = target_id) + ] } # EDGES edges <- data.table::copy(directed_edges) - edges <- edges[, .SD, .SDcols = c(source_id, target_id)] # we keep only the columns we need - edges <- unique(edges) # in case there are some duplicates - edges[, c(source_id, target_id) := lapply(.SD, as.character), .SDcols = c(source_id, target_id)] # we need to have character columns + edges <- data.table::data.table( + from = as.character(edges[[source_id]]), + to = as.character(edges[[target_id]]) + ) # canonical edge columns + edges <- unique(edges) ######################### Dynamics networks ********************* # define the time window - nodes_coupling <- nodes_coupling[order(time_variable), env = list(time_variable = time_variable)] - nodes_coupling[, time_variable := as.integer(time_variable), env = list(time_variable = time_variable)] - - first_year <- nodes_coupling[, min(as.integer(time_variable)), env = list(time_variable = time_variable)] - last_year <- nodes_coupling[, max(as.integer(time_variable)), env = list(time_variable = time_variable)] + nodes_coupling <- nodes_coupling[ + order(time_variable), + env = list(time_variable = time_variable) + ] + nodes_coupling[, + time_variable := as.integer(time_variable), + env = list(time_variable = time_variable) + ] + + first_year <- nodes_coupling[, + min(as.integer(time_variable)), + env = list(time_variable = time_variable) + ] + last_year <- nodes_coupling[, + max(as.integer(time_variable)), + env = list(time_variable = time_variable) + ] if (!is.null(time_window)) { if (last_year - first_year + 1 < time_window) { @@ -543,86 +349,105 @@ build_dynamic_networks2 <- function(nodes, tbl_coup_list <- list() for (year in all_years) { - nodes_of_the_year <- nodes_coupling[time_variable >= year & - time_variable < (year + time_window), env = list(time_variable = time_variable, year = year)] + nodes_of_the_year <- nodes_coupling[ + time_variable >= year & + time_variable < (year + time_window), + env = list(time_variable = time_variable, year = year) + ] if (time_variable != "fake_column") { - nodes_of_the_year[, time_window := paste0(year, "-", year + time_window - 1), env = list(year = year)] + nodes_of_the_year[, + time_window := paste0(year, "-", year + time_window - 1), + env = list(year = year) + ] - if (verbose == TRUE) + if (verbose == TRUE) { cli::cli_h1( "Generation of the network for the {.val {year}}-{.val {year + time_window - 1}} time window." ) + } } else { nodes_of_the_year <- nodes_of_the_year[, -c("fake_column")] } - edges_of_the_year <- edges[source_id %in% nodes_of_the_year[, source_id], env = list(source_id = source_id)] + node_ids <- nodes_of_the_year[[source_id]] + edges_of_the_year <- edges[from %in% node_ids] # size of nodes if (compute_size == TRUE) { - nb_cit <- edges_of_the_year[source_id %in% nodes_of_the_year[, source_id], .N, target_id, env = list(source_id = source_id, target_id = target_id)] + nb_cit <- edges_of_the_year[from %in% node_ids, .N, by = to] + data.table::setnames(nb_cit, "to", target_id) colnames(nb_cit)[colnames(nb_cit) == "N"] <- "node_size" - if ("node_size" %in% colnames(nodes_coupling) == TRUE) - { + if ("node_size" %in% colnames(nodes_coupling) == TRUE) { cli::cli_warn( "You already have a column name {.field node_size}. The content of the column will be replaced." ) } - nodes_of_the_year <- data.table::merge.data.table(nodes_of_the_year, - nb_cit, - by = target_id, - all.x = TRUE) + nodes_of_the_year <- data.table::merge.data.table( + nodes_of_the_year, + nb_cit, + by = target_id, + all.x = TRUE + ) nodes_of_the_year[is.na(node_size), node_size := 0] } - - # backbone - if (backbone_method == "statistical") { - # prepare backbone function - backbone_functions <- - data.table::data.table( - biblio_function = c( - rlang::expr(backbone::sdsm), - rlang::expr(backbone::fdsm), - rlang::expr(backbone::fixedfrow), - rlang::expr(backbone::fixedcol), - rlang::expr(backbone::fixedfill) - ), - method = c("sdsm", "fdsm", "fixedfrow", "fixedcol", "fixedfill") - ) - - backbone_functions <- backbone_functions[method == statistical_method][["biblio_function"]][[1]] - + if (projection_method == "statistical") { # Evaluate the expression and catch internal errors to backbone package + tryCatch( + { + from_pref <- paste0("A:", edges_of_the_year$from) + to_pref <- paste0("B:", edges_of_the_year$to) + bip_graph <- igraph::graph_from_data_frame( + data.frame(from = from_pref, to = to_pref), + directed = FALSE + ) + node_ids_pref <- paste0("A:", node_ids) + igraph::V(bip_graph)$type <- !(igraph::V(bip_graph)$name %in% + node_ids_pref) - tryCatch({ - # using backbone with edgelist is simpler but lead to error in backbone function - edges_of_the_year <- - rlang::expr((!!backbone_functions)( - B = as.data.frame(edges_of_the_year), - alpha = rlang::inject(alpha) - )) %>% - eval() %>% - data.table::as.data.table() - - }, error = function(e) { - stop( - "The backbone function failed with an error. Read the backbone documentation for more information. Error message: ", - e$message - ) - }) - } + backbone_graph <- do.call( + backbone::backbone_from_projection, + c(list(B = bip_graph, alpha = alpha, model = model), backbone_args) + ) + if (inherits(backbone_graph, "igraph")) { + edges_of_the_year <- igraph::as_data_frame( + backbone_graph, + what = "edges" + ) + } else if (!is.null(backbone_graph$backbone)) { + edges_of_the_year <- igraph::as_data_frame( + backbone_graph$backbone, + what = "edges" + ) + } else { + stop("The backbone function returned an unexpected object type.") + } + + edges_of_the_year <- data.table::as.data.table(edges_of_the_year) + edges_of_the_year[, from := sub("^A:", "", from)] + edges_of_the_year[, to := sub("^A:", "", to)] + edges_of_the_year[, from := sub("^B:", "", from)] + edges_of_the_year[, to := sub("^B:", "", to)] + }, + error = function(e) { + stop( + "The backbone function failed with an error. Read the backbone documentation for more information. Error message: ", + e$message + ) + } + ) + } # coupling - if (backbone_method == "structured") { + if (projection_method == "structured") { biblio_functions <- data.table::data.table( biblio_function = c( @@ -637,42 +462,50 @@ build_dynamic_networks2 <- function(nodes, ) ) - biblio_function <- biblio_functions[method == coupling_measure][["biblio_function"]][[1]] + biblio_function <- biblio_functions[method == cooccurrence_method][[ + "biblio_function" + ]][[1]] # evaluate the expression and catch internal errors to biblionetwork package - tryCatch({ - edges_of_the_year <- - rlang::expr((!!biblio_function)( - dt = edges_of_the_year, - source = rlang::inject(source_id), - ref = rlang::inject(target_id), - weight_threshold = rlang::inject(edges_threshold) + tryCatch( + { + edges_for_biblio <- data.table::copy(edges_of_the_year) + data.table::setnames( + edges_for_biblio, + c("from", "to"), + c(source_id, target_id) ) - ) %>% - eval() - - }, error = function(e) { - stop( - "The coupling function failed with an error. Read the biblionetwork documentation for more information. Error message: ", - e$message - ) - }) - + edges_of_the_year <- + rlang::expr((!!biblio_function)( + dt = edges_for_biblio, + source = rlang::inject(source_id), + ref = rlang::inject(target_id), + weight_threshold = rlang::inject(edges_threshold) + )) %>% + eval() + }, + error = function(e) { + stop( + "The coupling function failed with an error. Read the biblionetwork documentation for more information. Error message: ", + e$message + ) + } + ) } - edges_of_the_year[, source_id := from] - edges_of_the_year[, target_id := to] - # remove nodes with no edges if (keep_singleton == FALSE) { - nodes_of_the_year <- nodes_of_the_year[source_id %in% edges_of_the_year$from | - source_id %in% edges_of_the_year$to, env = list(source_id = source_id)] + nodes_of_the_year <- nodes_of_the_year[ + source_id %in% + edges_of_the_year$from | + source_id %in% edges_of_the_year$to, + env = list(source_id = source_id) + ] } # make tbl - if (length(all_years) == 1) - { + if (length(all_years) == 1) { tbl_coup_list <- tidygraph::tbl_graph( nodes = nodes_of_the_year, edges = edges_of_the_year, @@ -693,33 +526,62 @@ build_dynamic_networks2 <- function(nodes, if (filter_components == TRUE) { tbl_coup_list <- filter_components(tbl_coup_list, ...) } - return (tbl_coup_list) + return(tbl_coup_list) } -#' @rdname build_dynamic_networks +#' Build a single network +#' +#' Convenience wrapper around [build_dynamic_networks()] for a single network. +#' +#' @inheritParams build_dynamic_networks +#' @param projection_method Method used to build the single network. Must be +#' one of `"structured"` or `"statistical"`. +#' @param cooccurrence_method Cooccurrence method used by the structured workflow. #' @export - -build_network <- function(nodes, - directed_edges, - source_id, - target_id, - cooccurrence_method = c("coupling_angle","coupling_strength","coupling_similarity"), - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ...){ -graph <- build_dynamic_networks(nodes = nodes, - directed_edges = directed_edges, - source_id = source_id, - target_id = target_id, - cooccurrence_method = cooccurrence_method, - edges_threshold = edges_threshold, - compute_size = compute_size, - keep_singleton = keep_singleton, - filter_components = FALSE, - ..., - verbose = FALSE) -if(filter_components == TRUE) graph <- filter_components(graph, ...) -return(graph) +build_network <- function( + nodes, + directed_edges, + source_id, + target_id, + projection_method, + cooccurrence_method = c( + "coupling_angle", + "coupling_strength", + "coupling_similarity" + ), + edges_threshold = 1, + compute_size = FALSE, + keep_singleton = FALSE, + filter_components = FALSE, + ... +) { + if (missing(projection_method)) { + cli::cli_abort( + "Please provide {.arg projection_method}: either {.val structured} or {.val statistical}." + ) + } + projection_method <- match.arg( + projection_method, + c("structured", "statistical") + ) + + graph <- build_dynamic_networks( + nodes = nodes, + directed_edges = directed_edges, + source_id = source_id, + target_id = target_id, + projection_method = projection_method, + cooccurrence_method = cooccurrence_method, + edges_threshold = edges_threshold, + compute_size = compute_size, + keep_singleton = keep_singleton, + filter_components = FALSE, + ..., + verbose = FALSE + ) + if (filter_components == TRUE) { + graph <- filter_components(graph, ...) + } + graph } + diff --git a/R/build_dynamic_networks2.R b/R/build_dynamic_networks2.R deleted file mode 100644 index ecfb95b..0000000 --- a/R/build_dynamic_networks2.R +++ /dev/null @@ -1,536 +0,0 @@ -#' Creating One or Multiple Networks Using Structured or Statistical Backbone Extraction -#' -#' @description -#' `r lifecycle::badge("experimental")` -#' -#' `build_dynamic_networks2()` builds one or several networks (as tidygraph objects) -#' from a table of nodes and directed edges, with support for both structured cooccurrence -#' methods and statistical backbone extraction using the [backbone](https://github.com/zpneal/backbone) -#' package \insertCite{neal2022}{networkflow}. -#' The function is useful for constructing bibliometric or affiliation networks across -#' static or dynamic time windows. -#' -#' @param nodes Table of nodes and their metadata. One row per node. For example, a table -#' of articles with identifiers, authors, publication year, etc. -#' -#' @param directed_edges Table of edges representing the links between nodes and associated entities -#' (e.g., references, authors, affiliations). -#' -#' @param source_id Quoted name of the column giving the unique identifier of each node. -#' -#' @param target_id Quoted name of the column giving the identifier of the element linked to each node. -#' -#' @param time_variable Optional name of the column with a temporal variable (e.g., publication year). -#' -#' @param time_window Optional size of the time window (in units of `time_variable`) to construct temporal networks. -#' -#' @param backbone_method Method used to extract the network backbone. Choose between: -#' - `"structured"`: uses cooccurrence measures from the [biblionetwork](https://agoutsmedt.github.io/biblionetwork/) package; -#' - `"statistical"`: uses statistical models from the [backbone](https://github.com/djmurphy533/backbone) package. -#' Defaults to `"structured"`. -#' -#' @param model Null model used by the [backbone](https://github.com/zpneal/backbone) -#' package: one of `"sdsm"`, `"fdsm"`, `"fixedfill"`, `"fixedrow"`, `"fixedcol"`. Required if -#' `backbone_method = "statistical"`. These correspond to model names in `backbone` and are passed -#' through to the selected backbone function. -#' -#' -#' @param alpha Significance threshold for statistical backbone extraction. Required if -#' `backbone_method = "statistical"`. Lower values keep fewer edges (stricter filtering). -#' -#' @param coupling_measure For `backbone_method = "structured"`, choose the cooccurrence method: -#' - `"coupling_angle"` (biblio_coupling); -#' - `"coupling_strength"`; -#' - `"coupling_similarity"`. -#' -#' @param edges_threshold Threshold for edge weight filtering in structured methods. -#' -#' @param overlapping_window Logical. If `TRUE`, builds networks using rolling time windows. -#' -#' @param compute_size Logical. If `TRUE`, computes the number of incoming edges per node (e.g., citation count). -#' -#' @param keep_singleton Logical. If `FALSE`, removes nodes with no edges in the final network. -#' -#' @param filter_components Logical. If `TRUE`, keeps only the main component(s) using `networkflow::filter_components()`. -#' -#' @param ... Additional arguments passed to `filter_components()`. -#' -#' @param backbone_args Optional list of additional arguments passed to -#' [backbone::backbone_from_projection()]. Use this to set parameters like `mtc`, -#' `signed`, `missing_as_zero`, or `trials`. If `backbone_args` includes `alpha` or -#' `model`, those values override the corresponding function arguments. -#' -#' @param verbose Logical. If `TRUE`, displays progress messages. -#' -#' @details -#' `build_dynamic_networks2()` generalizes `build_dynamic_networks()` by adding support for -#' statistical backbone extraction using null models from the `backbone` package -#' \insertCite{neal2022}{networkflow}. The cooccurence methods used in -#' `build_dynamic_networks()` can be viewed as deterministic (structured) methods to extract -#' the network backbone. The backbone is defined as the significant edges in the network. -#' -#' As with `build_dynamic_networks()`, the function constructs networks for each time window. If `time_variable` and `time_window` are defined, the function constructs networks -#' for each time window (sliding or non-overlapping). Otherwise, it builds a single static network. -#' -#' If `backbone_method = "structured"`, cooccurrence edges are computed using bibliometric coupling -#' techniques. The term structured refers to deterministic methods based on thresholding cooccurrence measures. -#' If `backbone_method = "statistical"`, the function applies a `backbone` null model to the -#' edgelist for each time window and keeps only statistically significant edges at the chosen `alpha`. -#' The model is selected via `model` and follows `backbone`'s nomenclature: `"sdsm"`, `"fdsm"`, -#' `"fixedfill"`, `"fixedrow"`, or `"fixedcol"`. Only these models are currently supported. -#' -#' @examples -#' library(networkflow) -#' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") -#' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) -#' -#' # Structured backbone (cooccurrence) -#' net_structured <- build_dynamic_networks2( -#' nodes = nodes, -#' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", -#' time_window = 20, -#' backbone_method = "structured", -#' coupling_measure = "coupling_similarity", -#' edges_threshold = 1 -#' ) -#' -#' # Statistical backbone (backbone package) -#' net_statistical <- build_dynamic_networks2( -#' nodes = nodes, -#' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", -#' time_window = 20, -#' backbone_method = "statistical", -#' model = "sdsm", -#' alpha = 0.05, -#' backbone_args = list(mtc = "holm") -#' ) -#' -#' @return -#' - A single tidygraph object if `time_window` is `NULL`; -#' - A list of tidygraph objects (one per time window) otherwise. -#' -#' @seealso [biblionetwork::biblio_coupling()], [backbone::backbone_from_projection()] -#' -#' @references -#' \insertAllCited{} -#' -#' @export -#' - -build_dynamic_networks2 <- function( - nodes, - directed_edges, - source_id, - target_id, - time_variable = NULL, - time_window = NULL, - backbone_method = c("structured", "statistical"), - model = c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol"), - alpha = NULL, - coupling_measure = c( - "coupling_angle", - "coupling_strength", - "coupling_similarity" - ), - edges_threshold = 1, - overlapping_window = FALSE, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ..., - backbone_args = list(), - verbose = TRUE -) { - size <- node_size <- N <- method <- NULL - - # Making sure the table is a datatable - nodes <- data.table::data.table(nodes) - directed_edges <- data.table::data.table(directed_edges) - - # Checking the methods - backbone_methods <- c("structured", "statistical") - - coupling_measures <- c( - "coupling_angle", - "coupling_strength", - "coupling_similarity" - ) - - statistical_methods <- c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol") - - if (length(backbone_method) > 1) { - backbone_method <- match.arg(backbone_method, backbone_methods) - if (verbose == TRUE && missing(backbone_method)) { - cli::cli_alert_info( - "No backbone_method provided. Defaulting to {.val {backbone_method}}." - ) - } - } else { - backbone_method <- match.arg(backbone_method, backbone_methods) - } - - # check various setting for the structured/statistical methods - if (backbone_method == "structured") { - # Checking various problems: lacking method, - if (length(coupling_measure) > 1) { - cli::cli_abort( - c( - "For structured backbone extraction, you have to choose a coupling measure among: ", - "*" = "\"coupling_angle\";", - "*" = "\"coupling_strength\";", - "*" = "\"coupling_similarity\"." - ) - ) - } - - if (!coupling_measure %in% coupling_measures) { - cli::cli_abort( - c( - "For structured backbone extraction, you have to choose a coupling measure among: ", - "*" = "\"coupling_angle\";", - "*" = "\"coupling_strength\";", - "*" = "\"coupling_similarity\"." - ) - ) - } - } else if (backbone_method == "statistical") { - if (is.null(model) || length(model) > 1) { - cli::cli_abort( - c( - "For statistical backbone extraction, you have to choose a model: ", - "*" = "\"sdsm\";", - "*" = "\"fdsm\";", - "*" = "\"fixedfill\".", - "*" = "\"fixedrow\".", - "*" = "\"fixedcol\"." - ) - ) - } - - model <- match.arg(model, statistical_methods) - - # check if alpha is given - if (is.null(alpha) && is.null(backbone_args$alpha)) { - cli::cli_abort( - "For statistical backbone extraction, you have to choose a significance level alpha." - ) - } - } - - # warning if the source_id is not unique - if ( - nodes[, .N, source_id, env = list(source_id = source_id)][N > 1, .N] > 0 - ) { - cli::cli_alert_warning( - "Some identifiers in your column {.field {source_id}} in your nodes table are not unique. You need only one row per node." - ) - } - - # check settings for intertemporal networks - if (!is.null(time_window) & is.null(time_variable)) { - cli::cli_abort( - "You cannot have a {.emph time_window} if you don't give any column with a temporal variable. Put a column in {.emph time_variable} or remove the {.emph time_window}." - ) - } - - # VERBOSE - - if (verbose == TRUE) { - if (!missing(backbone_method)) { - cli::cli_alert_info(paste( - "Backbone method selected:", - backbone_method - )) - } - - if (keep_singleton == FALSE) { - cli::cli_alert_info( - "Keep_singleton == FALSE: removing the nodes that are alone with no edge. \n\n" - ) - } - } - - # CHECKING THE DATA - - # NODES - nodes_coupling <- data.table::copy(nodes) - nodes_coupling[, - source_id := as.character(source_id), - env = list(source_id = source_id) - ] - - if (is.null(time_variable)) { - time_variable <- "fake_column" - nodes_coupling[, - time_variable := 1, - env = list(time_variable = time_variable) - ] - } - - if ( - !target_id %in% colnames(nodes_coupling) & - compute_size == TRUE - ) { - cli::cli_abort( - "You don't have the column {.field {target_id}} in your nodes table. Set {.emph compute_size} to {.val FALSE}." - ) - } - - if (compute_size == TRUE) { - nodes_coupling[, - target_id := as.character(target_id), - env = list(target_id = target_id) - ] - } - - # EDGES - - edges <- data.table::copy(directed_edges) - edges <- edges[, .( - from = as.character(get(source_id)), - to = as.character(get(target_id)) - )] # canonical edge columns - edges <- unique(edges) - - ######################### Dynamics networks ********************* - - # define the time window - nodes_coupling <- nodes_coupling[ - order(time_variable), - env = list(time_variable = time_variable) - ] - nodes_coupling[, - time_variable := as.integer(time_variable), - env = list(time_variable = time_variable) - ] - - first_year <- nodes_coupling[, - min(as.integer(time_variable)), - env = list(time_variable = time_variable) - ] - last_year <- nodes_coupling[, - max(as.integer(time_variable)), - env = list(time_variable = time_variable) - ] - - if (!is.null(time_window)) { - if (last_year - first_year + 1 < time_window) { - cli::cli_alert_warning( - "Your time window is larger than the number of distinct values of {.field {time_variable}}" - ) - } - } - - if (is.null(time_window)) { - all_years <- first_year - time_window <- last_year - first_year + 1 - } else { - if (overlapping_window == TRUE) { - last_year <- last_year - time_window + 1 - all_years <- first_year:last_year - } else { - all_years <- seq(first_year, last_year, by = time_window) - if (all_years[length(all_years)] + (time_window - 1) > last_year) { - cli::cli_warn( - "Your last network is shorter than the other(s) because the cutting by time window does not give a round count. - The last time unity in your data is {.val {last_year}}, but the upper limit of your last time window is - {.val {all_years[length(all_years)] + (time_window - 1)}}." - ) - } - } - } - - # Prepare our list - tbl_coup_list <- list() - - for (year in all_years) { - nodes_of_the_year <- nodes_coupling[ - time_variable >= year & - time_variable < (year + time_window), - env = list(time_variable = time_variable, year = year) - ] - - if (time_variable != "fake_column") { - nodes_of_the_year[, - time_window := paste0(year, "-", year + time_window - 1), - env = list(year = year) - ] - - if (verbose == TRUE) { - cli::cli_h1( - "Generation of the network for the {.val {year}}-{.val {year + time_window - 1}} time window." - ) - } - } else { - nodes_of_the_year <- nodes_of_the_year[, -c("fake_column")] - } - - node_ids <- nodes_of_the_year[[source_id]] - edges_of_the_year <- edges[from %in% node_ids] - - # size of nodes - if (compute_size == TRUE) { - nb_cit <- edges_of_the_year[from %in% node_ids, .N, by = to] - data.table::setnames(nb_cit, "to", target_id) - - colnames(nb_cit)[colnames(nb_cit) == "N"] <- "node_size" - - if ("node_size" %in% colnames(nodes_coupling) == TRUE) { - cli::cli_warn( - "You already have a column name {.field node_size}. The content of the column will be replaced." - ) - } - - nodes_of_the_year <- data.table::merge.data.table( - nodes_of_the_year, - nb_cit, - by = target_id, - all.x = TRUE - ) - - nodes_of_the_year[is.na(node_size), node_size := 0] - } - - # backbone - - if (backbone_method == "statistical") { - # Evaluate the expression and catch internal errors to backbone package - tryCatch( - { - from_pref <- paste0("A:", edges_of_the_year$from) - to_pref <- paste0("B:", edges_of_the_year$to) - bip_graph <- igraph::graph_from_data_frame( - data.frame(from = from_pref, to = to_pref), - directed = FALSE - ) - node_ids_pref <- paste0("A:", node_ids) - igraph::V(bip_graph)$type <- !(igraph::V(bip_graph)$name %in% - node_ids_pref) - - backbone_graph <- do.call( - backbone::backbone_from_projection, - c(list(B = bip_graph, alpha = alpha, model = model), backbone_args) - ) - - if (inherits(backbone_graph, "igraph")) { - edges_of_the_year <- igraph::as_data_frame( - backbone_graph, - what = "edges" - ) - } else if (!is.null(backbone_graph$backbone)) { - edges_of_the_year <- igraph::as_data_frame( - backbone_graph$backbone, - what = "edges" - ) - } else { - stop("The backbone function returned an unexpected object type.") - } - - edges_of_the_year <- data.table::as.data.table(edges_of_the_year) - edges_of_the_year[, from := sub("^A:", "", from)] - edges_of_the_year[, to := sub("^A:", "", to)] - edges_of_the_year[, from := sub("^B:", "", from)] - edges_of_the_year[, to := sub("^B:", "", to)] - }, - error = function(e) { - stop( - "The backbone function failed with an error. Read the backbone documentation for more information. Error message: ", - e$message - ) - } - ) - } - - # coupling - if (backbone_method == "structured") { - biblio_functions <- - data.table::data.table( - biblio_function = c( - rlang::expr(biblionetwork::biblio_coupling), - rlang::expr(biblionetwork::coupling_strength), - rlang::expr(biblionetwork::coupling_similarity) - ), - method = c( - "coupling_angle", - "coupling_strength", - "coupling_similarity" - ) - ) - - biblio_function <- biblio_functions[method == coupling_measure][[ - "biblio_function" - ]][[1]] - - # evaluate the expression and catch internal errors to biblionetwork package - - tryCatch( - { - edges_for_biblio <- data.table::copy(edges_of_the_year) - data.table::setnames( - edges_for_biblio, - c("from", "to"), - c(source_id, target_id) - ) - edges_of_the_year <- - rlang::expr((!!biblio_function)( - dt = edges_for_biblio, - source = rlang::inject(source_id), - ref = rlang::inject(target_id), - weight_threshold = rlang::inject(edges_threshold) - )) %>% - eval() - }, - error = function(e) { - stop( - "The coupling function failed with an error. Read the biblionetwork documentation for more information. Error message: ", - e$message - ) - } - ) - } - - # remove nodes with no edges - if (keep_singleton == FALSE) { - nodes_of_the_year <- nodes_of_the_year[ - source_id %in% - edges_of_the_year$from | - source_id %in% edges_of_the_year$to, - env = list(source_id = source_id) - ] - } - - # make tbl - if (length(all_years) == 1) { - tbl_coup_list <- tidygraph::tbl_graph( - nodes = nodes_of_the_year, - edges = edges_of_the_year, - directed = FALSE, - node_key = source_id - ) - } else { - tbl_coup_list[[paste0(year, "-", year + time_window - 1)]] <- - tidygraph::tbl_graph( - nodes = nodes_of_the_year, - edges = edges_of_the_year, - directed = FALSE, - node_key = source_id - ) - } - } - - if (filter_components == TRUE) { - tbl_coup_list <- filter_components(tbl_coup_list, ...) - } - return(tbl_coup_list) -} diff --git a/R/color_networks.R b/R/color_networks.R index 73ecb80..759fe07 100644 --- a/R/color_networks.R +++ b/R/color_networks.R @@ -58,18 +58,16 @@ #' @examples #' library(networkflow) #' - #' nodes <- Nodes_stagflation |> - #' dplyr::rename(ID_Art = ItemID_Ref) |> - #' dplyr::filter(Type == "Stagflation") + #' nodes <- networkflow::Nodes_stagflation |> + #' dplyr::filter(source_type == "Stagflation") #' - #' references <- Ref_stagflation |> - #' dplyr::rename(ID_Art = Citing_ItemID_Ref) + #' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, - #' source_id = "ID_Art", - #' target_id = "ItemID_Ref", - #' time_variable = "Year", + #' source_id = "source_id", + #' target_id = "target_id", + #' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -272,3 +270,4 @@ color_alluvial <- function(alluv_dt, return(alluv_dt) } + diff --git a/R/dynamic_network_cooccurrence.R b/R/dynamic_network_cooccurrence.R index 6ff0705..2e0a8d3 100644 --- a/R/dynamic_network_cooccurrence.R +++ b/R/dynamic_network_cooccurrence.R @@ -94,18 +94,16 @@ dynamic_network_cooccurrence <- function(nodes = NULL, #' of tidygraph networks, for each time window. #' #' @examples - #' nodes <- Nodes_stagflation |> - #' dplyr::rename(ID_Art = ItemID_Ref) |> - #' dplyr::filter(Type == "Stagflation") - #' - #' references <- Ref_stagflation |> - #' dplyr::rename(ID_Art = Citing_ItemID_Ref) - #' - #' temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, - #' directed_edges = references, - #' source_column = "ID_Art", - #' target_column = "ItemID_Ref", - #' time_variable = "Year", +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") +#' +#' references <- networkflow::Ref_stagflation +#' +#' temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, +#' directed_edges = references, +#' source_column = "source_id", +#' target_column = "target_id", + #' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = NULL, #' edges_threshold = 1, diff --git a/R/extract_tfidf.R b/R/extract_tfidf.R index 11eb5fd..1b5e69c 100644 --- a/R/extract_tfidf.R +++ b/R/extract_tfidf.R @@ -94,18 +94,16 @@ #' the top of your grouping variables. #' #' @examples -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 10, #' edges_threshold = 1, @@ -119,10 +117,10 @@ #' library(stopwords) #' tfidf <- extract_tfidf(temporal_networks, #' n_gram = 4, -#' text_columns = "Title", +#' text_columns = "source_title", #' grouping_columns = "cluster_leiden", #' grouping_across_list = TRUE, -#' clean_word_method = "lemmatise") +#' clean_word_method = "lemmatize") #' #' tfidf[[1]] #' @@ -205,3 +203,4 @@ extract_tfidf <- function(data, return(term_list) } + diff --git a/R/intertemporal_cluster_naming.R b/R/intertemporal_cluster_naming.R index 29079f5..cd9840f 100644 --- a/R/intertemporal_cluster_naming.R +++ b/R/intertemporal_cluster_naming.R @@ -58,20 +58,18 @@ intertemporal_cluster_naming <- function(list_graph = NA, #' @examples #' library(biblionetwork) #' library(magrittr) - #' library(tidygraph) - #' - #' nodes <- Nodes_stagflation %>% - #' dplyr::rename(ID_Art = ItemID_Ref) %>% - #' dplyr::filter(Type == "Stagflation") - #' - #' references <- Ref_stagflation %>% - #' dplyr::rename(ID_Art = Citing_ItemID_Ref) - #' - #' temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, - #' directed_edges = references, - #' source_column = "ID_Art", - #' target_column = "ItemID_Ref", - #' time_variable = "Year", +#' library(tidygraph) +#' +#' nodes <- networkflow::Nodes_stagflation %>% +#' dplyr::filter(source_type == "Stagflation") +#' +#' references <- networkflow::Ref_stagflation +#' +#' temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, +#' directed_edges = references, +#' source_column = "source_id", +#' target_column = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 15, #' edges_threshold = 1, @@ -83,11 +81,11 @@ intertemporal_cluster_naming <- function(list_graph = NA, #' function(tbl) tbl %N>% #' mutate(clusters = tidygraph::group_louvain())) #' - #' intertemporal_cluster_naming(temporal_networks, - #' cluster_column = "clusters", - #' node_key = "ID_Art", - #' threshold_similarity = 0.51, - #' similarity_type = "partial") +#' intertemporal_cluster_naming(temporal_networks, +#' cluster_column = "clusters", +#' node_key = "source_id", +#' threshold_similarity = 0.51, +#' similarity_type = "partial") #' #' @export diff --git a/R/launch_network_app.R b/R/launch_network_app.R index ec3e0c7..96ac048 100644 --- a/R/launch_network_app.R +++ b/R/launch_network_app.R @@ -30,18 +30,18 @@ #' library(networkflow) #' library(dplyr) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::filter(Type == "Stagflation") |> -#' dplyr::rename(ID_Art = ItemID_Ref) +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") |> +#' dplyr::mutate(source_id = as.character(source_id)) #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' g <- build_network( #' nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", +#' source_id = "source_id", +#' target_id = "target_id", +#' projection_method = "structured", #' cooccurrence_method = "coupling_similarity", #' edges_threshold = 1, #' compute_size = FALSE, @@ -58,10 +58,10 @@ #' launch_network_app( #' graph_tbl = g, #' cluster_id = "cluster_leiden", -#' cluster_information = c("Author", "Title", "Year", "Journal"), +#' cluster_information = c("source_author", "source_title", "source_year", "source_journal"), #' cluster_tooltip = "Cluster", -#' node_id = "ID_Art", -#' node_tooltip = "Author_date", +#' node_id = "source_id", +#' node_tooltip = "source_label", #' node_size = NULL, #' color = NULL, #' layout = "kk" @@ -72,9 +72,9 @@ #' g_list <- build_dynamic_networks( #' nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' time_window = 20, #' cooccurrence_method = "coupling_similarity", #' edges_threshold = 1, @@ -93,9 +93,9 @@ #' launch_network_app( #' graph_tbl = g_list, #' cluster_id = "cluster_leiden", -#' cluster_information = c("Author", "Title", "Year", "Journal"), -#' node_id = "ID_Art", -#' node_tooltip = "Author_date", +#' cluster_information = c("source_author", "source_title", "source_year", "source_journal"), +#' node_id = "source_id", +#' node_tooltip = "source_label", #' node_size = NULL, #' color = NULL, #' layout = "kk" diff --git a/R/layout_networks.R b/R/layout_networks.R index fa62c76..41e4756 100644 --- a/R/layout_networks.R +++ b/R/layout_networks.R @@ -51,18 +51,16 @@ #' @examples #' library(networkflow) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -70,7 +68,7 @@ #' filter_components = TRUE) #' #' temporal_networks <- layout_networks(temporal_networks, -#' node_id = "ID_Art", +#' node_id = "source_id", #' layout = "fr", #' compute_dynamic_coordinates = TRUE) #' @@ -184,3 +182,4 @@ join_coordinates <- function(graphs, } return(graphs) } + diff --git a/R/merge_dynamic_clusters.R b/R/merge_dynamic_clusters.R index 798d8cf..d7b77f1 100644 --- a/R/merge_dynamic_clusters.R +++ b/R/merge_dynamic_clusters.R @@ -57,18 +57,16 @@ #' @examples #' library(networkflow) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 10, #' edges_threshold = 1, @@ -81,7 +79,7 @@ #' #' temporal_networks <- merge_dynamic_clusters(temporal_networks, #' cluster_id = "cluster_leiden", -#' node_id = "ID_Art", +#' node_id = "source_id", #' threshold_similarity = 0.51, #' similarity_type = "partial") #' @@ -259,3 +257,4 @@ add_dynamic_cluster_to_edges <- function(graph, graph <- graph %E>% dplyr::left_join(cluster_correspondance, by = cluster_id) } + diff --git a/R/name_clusters.R b/R/name_clusters.R index e155d6a..c936fb7 100644 --- a/R/name_clusters.R +++ b/R/name_clusters.R @@ -91,18 +91,16 @@ #' @examples #' library(networkflow) #' -#' nodes <- Nodes_stagflation |> -#' dplyr::rename(ID_Art = ItemID_Ref) |> -#' dplyr::filter(Type == "Stagflation") +#' nodes <- networkflow::Nodes_stagflation |> +#' dplyr::filter(source_type == "Stagflation") #' -#' references <- Ref_stagflation |> -#' dplyr::rename(ID_Art = Citing_ItemID_Ref) +#' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, -#' source_id = "ID_Art", -#' target_id = "ItemID_Ref", -#' time_variable = "Year", +#' source_id = "source_id", +#' target_id = "target_id", +#' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -121,7 +119,7 @@ #' method = "tidygraph_functions", #' name_merged_clusters = FALSE, #' cluster_id = "cluster_leiden", -#' label_columns = c("Author", "Year"), +#' label_columns = c("source_author", "source_year"), #' tidygraph_function = tidygraph::centrality_pagerank()) #' #' temporal_networks_with_names[[1]] @@ -130,7 +128,7 @@ #' #' temporal_networks <- merge_dynamic_clusters(temporal_networks, #' cluster_id = "cluster_leiden", -#' node_id = "ID_Art", +#' node_id = "source_id", #' threshold_similarity = 0.51, #' similarity_type = "partial") #' @@ -138,9 +136,9 @@ #' method = "tf-idf", #' name_merged_clusters = TRUE, #' cluster_id = "dynamic_cluster_leiden", -#' text_columns = "Title", +#' text_columns = "source_title", #' nb_terms_label = 5, -#' clean_word_method = "lemmatise") +#' clean_word_method = "lemmatize") #' #' temporal_networks_with_names[[1]] #' @@ -262,3 +260,4 @@ name_clusters <- function(graphs, return(graphs) } + diff --git a/R/networks_to_alluv.R b/R/networks_to_alluv.R index a9439c5..e9128ab 100644 --- a/R/networks_to_alluv.R +++ b/R/networks_to_alluv.R @@ -55,18 +55,16 @@ networks_to_alluv <- function(graphs, #' @examples #' library(networkflow) #' - #' nodes <- Nodes_stagflation |> - #' dplyr::rename(ID_Art = ItemID_Ref) |> - #' dplyr::filter(Type == "Stagflation") + #' nodes <- networkflow::Nodes_stagflation |> + #' dplyr::filter(source_type == "Stagflation") #' - #' references <- Ref_stagflation |> - #' dplyr::rename(ID_Art = Citing_ItemID_Ref) + #' references <- networkflow::Ref_stagflation #' #' temporal_networks <- build_dynamic_networks(nodes = nodes, #' directed_edges = references, - #' source_id = "ID_Art", - #' target_id = "ItemID_Ref", - #' time_variable = "Year", + #' source_id = "source_id", + #' target_id = "target_id", + #' time_variable = "source_year", #' cooccurrence_method = "coupling_similarity", #' time_window = 20, #' edges_threshold = 1, @@ -81,7 +79,7 @@ networks_to_alluv <- function(graphs, #' #' temporal_networks <- merge_dynamic_clusters(temporal_networks, #' cluster_id = "cluster_leiden", - #' node_id = "ID_Art", + #' node_id = "source_id", #' threshold_similarity = 0.51, #' similarity_type = "partial") #' @@ -89,9 +87,9 @@ networks_to_alluv <- function(graphs, #' method = "tf-idf", #' name_merged_clusters = TRUE, #' cluster_id = "dynamic_cluster_leiden", - #' text_columns = "Title", + #' text_columns = "source_title", #' nb_terms_label = 5, - #' clean_word_method = "lemmatise") + #' clean_word_method = "lemmatize") #' #' temporal_networks <- color_networks(graphs = temporal_networks, #' column_to_color = "dynamic_cluster_leiden", @@ -99,7 +97,7 @@ networks_to_alluv <- function(graphs, #' #' alluv_dt <- networks_to_alluv(temporal_networks, #' intertemporal_cluster_column = "dynamic_cluster_leiden", - #' node_id = "ID_Art") + #' node_id = "source_id") #' #' alluv_dt[1:5] #' @@ -155,3 +153,4 @@ networks_to_alluv <- function(graphs, return (alluv_dt) } + diff --git a/R/plot_networks.R b/R/plot_networks.R index cfb01e0..4dc7972 100644 --- a/R/plot_networks.R +++ b/R/plot_networks.R @@ -172,8 +172,8 @@ plot_network <- function(graph, graph <- graph %E>% dplyr::mutate(weight = 1) } - if(! node_size_column %in% colnames(graph %N>% as.data.frame()) | is.null(node_size_column)){ - cli::cli_alert_info("No column `weight` found in edges data. All weight will equal 1.") + if (is.null(node_size_column) || !node_size_column %in% colnames(graph %N>% as.data.frame())) { + cli::cli_alert_info("No `node_size_column` found in node data. All node sizes will be set to 1.") graph <- graph %N>% dplyr::mutate(node_size = 1) node_size_column <- "node_size" diff --git a/README.Rmd b/README.Rmd index b5cb0e8..d577fbc 100644 --- a/README.Rmd +++ b/README.Rmd @@ -3,10 +3,6 @@ output: github_document: toc: false toc_depth: 3 - -### -### Bibliography settings -### bibliography: ./inst/REFERENCES.bib csl: ./inst/chicago-author-date.csl suppress-bibliography: false @@ -31,32 +27,34 @@ knitr::opts_chunk$set( [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) -The goal of networkflow (a workflow for networks) is to propose a series of functions to make -it easier and quicker to manipulats networks. It mainly targets working on bibliometric networks -(see the [biblionetwork](https://github.com/agoutsmedt/biblionetwork) package for creating such networks). -This package heavily relies on [igraph](https://igraph.org/r/) and [tidygraph](https://tidygraph.data-imaginist.com/index.html), -and aims at producing ready-made networks for projecting them using [ggraph](https://ggraph.data-imaginist.com/). -This package aims at helping the users to follow more quickly and easily the main steps of network manipulation, -from creating the graph, through detecting clusters, to projecting it. Please see -`vignette("workflow-network")` for details on the workflow for dealing with a unique -network. +`networkflow` provides a complete workflow to build, structure, and explore +networks from tabular data. -Networkflow also proposes a worfklow to deal with a list of networks, in order to develop a -dynamic analysis. It implements a method to merge clusters across successive networks, -to identify inter-temporal clusters. It also develops corresponding visualisations to -display the evolution of clusters across networks. `vignette("exploring_dynamic_networks")` -gives an example of the workflow for dynamic networks. You can also find illustrations for this -method in ["An Independent European Macroeconomics? A History of European Macroeconomics -through the Lens of the European Economic Review](https://aurelien-goutsmedt.com/publication/eer-history/). +Its key feature is a built-in dynamic analysis workflow: the package can +build networks across time windows, detect clusters in each window, and link +clusters across periods to track their evolution. +More broadly, `networkflow` supports the full analysis pipeline, from network +construction to interpretation and visualization, including clustering, layout +and color preparation, static plotting, and interactive exploration with a +Shiny app. +The package was developed with projected networks in mind (for example, +article -> reference), but it can also be used more generally once data are +represented as `tbl_graph` objects. -You can cite this package as: +The package includes: -```{r} -citation("networkflow") -``` +- network construction (`build_network()`, `build_dynamic_networks()`), +- clustering and inter-temporal matching (`add_clusters()`, `merge_dynamic_clusters()`), +- interpretation (`name_clusters()`, `extract_tfidf()`), +- visualization (`layout_networks()`, `color_networks()`, `plot_networks()`), +- interactive exploration (`launch_network_app()`). +For a full walkthrough, see: + +- `vignette("networkflow_presentation")` +- https://agoutsmedt.github.io/networkflow/ ## Installation @@ -67,3 +65,41 @@ install.packages("devtools") devtools::install_github("agoutsmedt/networkflow") ``` +## Quick start + +```{r eval = FALSE} +library(networkflow) + +nodes <- subset(Nodes_stagflation, source_type == "Stagflation") +references <- Ref_stagflation + +g <- build_network( + nodes = nodes, + directed_edges = references, + source_id = "source_id", + target_id = "target_id", + projection_method = "structured", + cooccurrence_method = "coupling_similarity", + edges_threshold = 1, + keep_singleton = FALSE +) + +g <- add_clusters( + graphs = g, + clustering_method = "leiden", + objective_function = "modularity", + seed = 123 +) + +g <- layout_networks(g, node_id = "source_id", layout = "kk") +g <- color_networks(g, column_to_color = "cluster_leiden") + +plot_networks( + graphs = g, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden", + node_size_column = NULL, + color_column = "color" +) +``` diff --git a/README.html b/README.html new file mode 100644 index 0000000..bd1dc19 --- /dev/null +++ b/README.html @@ -0,0 +1,683 @@ + + + + + + + + + + + + + + + + + + + + + +

networkflow

+ + +

R-CMD-check Lifecycle: experimental

+ + +

networkflow provides a complete workflow to build, +structure, and explore networks from tabular data.

+

Its key feature is a built-in dynamic analysis workflow: the package +can build networks across time windows, detect clusters in each window, +and link clusters across periods to track their evolution.

+

More broadly, networkflow supports the full analysis +pipeline, from network construction to interpretation and visualization, +including clustering, layout and color preparation, static plotting, and +interactive exploration with a Shiny app.

+

The package was developed with projected networks in mind (for +example, article -> reference), but it can also be used more +generally once data are represented as tbl_graph +objects.

+

The package includes:

+ +

For a full walkthrough, see:

+ +

Installation

+

You can install the development version from GitHub with:

+
install.packages("devtools")
+devtools::install_github("agoutsmedt/networkflow")
+

Quick start

+
library(networkflow)
+
+nodes <- subset(Nodes_stagflation, source_type == "Stagflation")
+references <- Ref_stagflation
+
+g <- build_network(
+  nodes = nodes,
+  directed_edges = references,
+  source_id = "source_id",
+  target_id = "target_id",
+  projection_method = "structured",
+  cooccurrence_method = "coupling_similarity",
+  edges_threshold = 1,
+  keep_singleton = FALSE
+)
+
+g <- add_clusters(
+  graphs = g,
+  clustering_method = "leiden",
+  objective_function = "modularity",
+  seed = 123
+)
+
+g <- layout_networks(g, node_id = "source_id", layout = "kk")
+g <- color_networks(g, column_to_color = "cluster_leiden")
+
+plot_networks(
+  graphs = g,
+  x = "x",
+  y = "y",
+  cluster_label_column = "cluster_leiden",
+  node_size_column = NULL,
+  color_column = "color"
+)
+ + + diff --git a/README.md b/README.md index 2bd3eef..52d921c 100644 --- a/README.md +++ b/README.md @@ -10,52 +10,36 @@ experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) -The goal of networkflow (a workflow for networks) is to propose a series -of functions to make it easier and quicker to manipulats networks. It -mainly targets working on bibliometric networks (see the -[biblionetwork](https://github.com/agoutsmedt/biblionetwork) package for -creating such networks). This package heavily relies on -[igraph](https://igraph.org/r/) and -[tidygraph](https://tidygraph.data-imaginist.com/index.html), and aims -at producing ready-made networks for projecting them using -[ggraph](https://ggraph.data-imaginist.com/). This package aims at -helping the users to follow more quickly and easily the main steps of -network manipulation, from creating the graph, through detecting -clusters, to projecting it. Please see `vignette("workflow-network")` -for details on the workflow for dealing with a unique network. - -Networkflow also proposes a worfklow to deal with a list of networks, in -order to develop a dynamic analysis. It implements a method to merge -clusters across successive networks, to identify inter-temporal -clusters. It also develops corresponding visualisations to display the -evolution of clusters across networks. -`vignette("exploring_dynamic_networks")` gives an example of the -workflow for dynamic networks. You can also find illustrations for this -method in [“An Independent European Macroeconomics? A History of -European Macroeconomics through the Lens of the European Economic -Review](https://aurelien-goutsmedt.com/publication/eer-history/). - -You can cite this package as: +`networkflow` provides a complete workflow to build, structure, and +explore networks from tabular data. -``` r -citation("networkflow") -#> -#> Pour citer le package 'networkflow' dans une publication, utilisez : -#> -#> Goutsmedt A, Truc A (2022). _networkflow: Functions For A Workflow To -#> Manipulate Networks_. https://github.com/agoutsmedt/networkflow, -#> https://agoutsmedt.github.io/networkflow/. -#> -#> Une entrée BibTeX pour les utilisateurs LaTeX est -#> -#> @Manual{, -#> title = {networkflow: Functions For A Workflow To Manipulate Networks}, -#> author = {Aurélien Goutsmedt and Alexandre Truc}, -#> year = {2022}, -#> note = {https://github.com/agoutsmedt/networkflow, -#> https://agoutsmedt.github.io/networkflow/}, -#> } -``` +Its key feature is a built-in dynamic analysis workflow: the package can +build networks across time windows, detect clusters in each window, and +link clusters across periods to track their evolution. + +More broadly, `networkflow` supports the full analysis pipeline, from +network construction to interpretation and visualization, including +clustering, layout and color preparation, static plotting, and +interactive exploration with a Shiny app. + +The package was developed with projected networks in mind (for example, +article -\> reference), but it can also be used more generally once data +are represented as `tbl_graph` objects. + +The package includes: + +- network construction (`build_network()`, `build_dynamic_networks()`), +- clustering and inter-temporal matching (`add_clusters()`, + `merge_dynamic_clusters()`), +- interpretation (`name_clusters()`, `extract_tfidf()`), +- visualization (`layout_networks()`, `color_networks()`, + `plot_networks()`), +- interactive exploration (`launch_network_app()`). + +For a full walkthrough, see: + +- `vignette("networkflow_presentation")` +- ## Installation @@ -66,3 +50,42 @@ You can install the development version from install.packages("devtools") devtools::install_github("agoutsmedt/networkflow") ``` + +## Quick start + +``` r +library(networkflow) + +nodes <- subset(Nodes_stagflation, source_type == "Stagflation") +references <- Ref_stagflation + +g <- build_network( + nodes = nodes, + directed_edges = references, + source_id = "source_id", + target_id = "target_id", + projection_method = "structured", + cooccurrence_method = "coupling_similarity", + edges_threshold = 1, + keep_singleton = FALSE +) + +g <- add_clusters( + graphs = g, + clustering_method = "leiden", + objective_function = "modularity", + seed = 123 +) + +g <- layout_networks(g, node_id = "source_id", layout = "kk") +g <- color_networks(g, column_to_color = "cluster_leiden") + +plot_networks( + graphs = g, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden", + node_size_column = NULL, + color_column = "color" +) +``` diff --git a/_pkgdown.yml b/_pkgdown.yml index 2dcb569..fc605b4 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -10,15 +10,18 @@ reference: Functions for creating one or multiple networks and to filter the networks. contents: - build_dynamic_networks + - build_network - filter_components - title: "Step 2: Clustering" desc: > - Functions for detected clusters and manipulate them. + Functions for detecting clusters and interpreting them. contents: - add_clusters - merge_dynamic_clusters - name_clusters + - add_node_roles + - extract_tfidf - title: "Step 3: Plot networks" desc: > @@ -31,16 +34,12 @@ reference: - prepare_label_networks - plot_alluvial - plot_networks + - launch_network_app -- title: "Step 4: Analysis networks" - desc: > - Functions for exploring the content of the networks. - contents: - - extract_tfidf - title: "Included datasets" desc: "Data on articles about stagflation from Goutsmedt (2021) 'From the Stagflation to the Great Inflation'" -- contents: + contents: - contains("stagflation") - ends_with("coupling") diff --git a/data/Authors_stagflation.rda b/data/Authors_stagflation.rda index f527d637dd9647733a5f25d9051d07cb0934c6fb..0debf64bab642bde5fd266bb2cff058420ff18c8 100644 GIT binary patch literal 2221 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 S4cZp}#oUoj6eKCABHuu=R~`@m diff --git a/data/Nodes_coupling.rda b/data/Nodes_coupling.rda index 302a2f28d0216485ee36e40dfac5198c568700a9..5b2f7a4c2913b9bb6174917b0e7e0ace0331fdc9 100644 GIT binary patch literal 8264 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 z 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 GWdH!A{N;QA literal 7430 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

_< z1_e#x@AkUF;|=uZG{c~<*pZd6gKTbdoL@u+O(aPxxQA8Kc8q8lV!|YlM8QzJNEr+& z9b~2lo)|0z1z?c0-H-*Apph=>?KSC#TWz`oBrO9|IOCLFQ?HG(-QJkR?o`@bJe0=+ z65cv(ywM2@F3!x%=Y)!>qV^_W;WTfiL3C^mnFz?f)4VBnCrg!yq=@MbT_dEss0saC zLz8?qQKvS}(Ggj!>PMnJ8W&QUH|CJs+H9Fg0Jb9{#RfAy2Nq3`qQ|jB4%eBvq#@@i zKzeNvCS9t4mtCZ1tt(|~NYo*X#6?S>rB!l(VU&|b1~FO1NTD#nCJ>b{frb)kBNhyR zB4p8fUYCFyn$0zkPHDo0V!;`nHF46h$l$UD5(OYhX#+FiG#u59HL0t<#*kgMG*oy4 zuT9`c97L0eYAVElf+{GAf-xfm1!Aa3YywE}DdI}7iwamvH93d{ZT&}5nk{KuHFHWS z3Q>gM0C1Xc3T49y@rKS`jSkrP8ZvZb_)nk3A0J1%C6|6TwHX(o9S41l1g(_zl|osU z2oi%{F(oqzQ@h{tFS+Q&L{vag6p9L>#YF5BBwf|0W8ztDNJ#ZXB*Ca#*maT?j8;K4 zN?cQQAY4KzAf$xPPhNOJpeYrQYo8JUG6t+D=!H}=CtJVdbU`he>R#s^4C|S*I}2Fo zB!uc*l^K%Yzi|91!z~VCR(R zxz4f$k_eKoKuLz=>wc+K7P%|102M~x=*x(HktQJKhlNheQUw=q)n(^f` zTeyV+fteOS6_Bt>$;33{N(I6dM;V8rbBvx4OKEA(@ooz-&9;!Ug$#gu65lM%`U;#@ zq+FQTYap@+!WY+hlfKtkIIwYx4^vdjtI7^Y_8o(CR7^93mF^m*W)a7z_7&WQ+T8ez zXE(Kn;$vWOAC0|@Moq_Nj$J@fKp7%T#~QphN+9-OZrsY97{egf42f$oDer3sBzDI- z=Q2K6jt#bFlsdF>#Fmqu6yDIuy*F|#MphY-p_!YwFrqFLpz@X7p4RcgPn+T#pk2%0;X)P%mI4^H(1)O@-Y{Nk3 zsv;^Pj|ANgQyY>T5C);d3$PieXt~LdUd3Tqlh|M)*Qn#VwGQpVBh_Z?yC{dsw zSZSy%oh>rBu+^a!4tH$3*=PZ(6D)>_GK}faOrR_Pw2Bh=*1QWZW(Kknj4u@7A)4^H zHL((S7^Nzv5MT^ZTH`KBQ)XK?R*AW{6fOzmiH|8zm{7_|WWYz^ty1xrMvn(1*O59e7jAs71AzAr2-rvZRKYuu@GyiJB!CIERa2b|oZ9Ro$@6 z)+ohiKVOrRbGU0pim4McQCeM(HUiKcbz#xGNMpNUl5JUIb-ORGQ-E1nbZi4?X6c0p z=CW!-7gT8FGm&$edKD~yjD&CDpDJv32a6P0PcIr+$I@whLJ|fZ;6L$qBvXY62;mG% E&}QhOVE_OC diff --git a/data/Nodes_stagflation.rda b/data/Nodes_stagflation.rda index f5ca194c783c3e93b8ad4dbacf735fac1f5d9b7a..3c5083379e26231b68a2f46f738bf5f87bdcdf2f 100644 GIT binary patch literal 24872 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 QU0$UCwL#1sop0a#4}=d>O8@`> literal 21114 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 R1ylNqxgwk>NL!$=I{=HYc)tJu diff --git a/data/Ref_stagflation.rda b/data/Ref_stagflation.rda index 3e1458674a35729d50437c1f368c9f572b8ef0e7..563bf677134ebd748b5b30055494b377f956e9e3 100644 GIT binary patch literal 97213 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 diff --git a/inst/data-raw/creating_network_data.R b/inst/data-raw/creating_network_data.R index a56b442..5cf49b1 100644 --- a/inst/data-raw/creating_network_data.R +++ b/inst/data-raw/creating_network_data.R @@ -2,13 +2,13 @@ library(biblionetwork) library(data.table) Nodes_coupling <- as.data.table(Nodes_stagflation) -Nodes_coupling <- Nodes_coupling[Type == "Stagflation" & ItemID_Ref %in% Ref_stagflation$Citing_ItemID_Ref] -Nodes_coupling$ItemID_Ref <- as.character(Nodes_coupling$ItemID_Ref) -Nodes_coupling <- Nodes_coupling[,-"Type"] +Nodes_coupling <- Nodes_coupling[source_type == "Stagflation" & source_id %in% Ref_stagflation$source_id] +Nodes_coupling$source_id <- as.character(Nodes_coupling$source_id) +Nodes_coupling <- Nodes_coupling[,-"source_type"] -Edges_coupling <- biblio_coupling(Ref_stagflation, "Citing_ItemID_Ref", "ItemID_Ref") -Edges_coupling <- Edges_coupling[from %in% Nodes_coupling$ItemID_Ref] -Edges_coupling <- Edges_coupling[to %in% Nodes_coupling$ItemID_Ref] +Edges_coupling <- biblio_coupling(Ref_stagflation, "source_id", "target_id") +Edges_coupling <- Edges_coupling[from %in% Nodes_coupling$source_id] +Edges_coupling <- Edges_coupling[to %in% Nodes_coupling$source_id] use_data(Nodes_coupling, overwrite = TRUE) use_data(Edges_coupling, overwrite = TRUE) diff --git a/man/Authors_stagflation.Rd b/man/Authors_stagflation.Rd index 14abb5b..8d0b5b4 100644 --- a/man/Authors_stagflation.Rd +++ b/man/Authors_stagflation.Rd @@ -5,11 +5,11 @@ \alias{Authors_stagflation} \title{List Of Authors Of The Articles and Books Explaining the 1970s US Stagflation.} \format{ -A data frame with 558 rows and 7 variables: +A data frame with 231 rows and 3 variables: \describe{ -\item{ItemID_Ref}{Identifier of the document published by the author} -\item{Author}{Author of the document} -\item{Order}{Use this as a label for nodes} +\item{source_id}{Identifier of the document published by the author} +\item{author_name}{Author of the document} +\item{author_order}{Author order in the document author list} } } \source{ diff --git a/man/Edges_coupling.Rd b/man/Edges_coupling.Rd index a159d72..d89cc03 100644 --- a/man/Edges_coupling.Rd +++ b/man/Edges_coupling.Rd @@ -5,7 +5,7 @@ \alias{Edges_coupling} \title{Edges For Bibliographic Coupling Network Of Articles and Books Explaining the 1970s US Stagflation.} \format{ -A data frame with 154 rows and 6 variables: +A data frame with 2593 rows and 5 variables: \describe{ \item{from}{Identifier of the Source document on stagflation, in character format} \item{to}{Identifier of the Target document on stagflation, in character format} @@ -22,7 +22,7 @@ Edges_coupling } \description{ A dataset containing the edges of the bibliographic coupling network of articles and books on stagflation. -Built by using \link{Ref_stagflation}: \code{biblionetwork::biblio_coupling(Ref_stagflation,"Citing_ItemID_Ref","ItemID_Ref")}. +Built by using \link{Ref_stagflation}: \code{biblionetwork::biblio_coupling(Ref_stagflation,"source_id","target_id")}. Could be used with \link{Nodes_coupling} to create a network with tidygraph. } \keyword{datasets} diff --git a/man/Nodes_coupling.Rd b/man/Nodes_coupling.Rd index c7eeebb..fecea97 100644 --- a/man/Nodes_coupling.Rd +++ b/man/Nodes_coupling.Rd @@ -7,12 +7,12 @@ \format{ A data frame with 154 rows and 6 variables: \describe{ -\item{ItemID_Ref}{Identifier of the document on stagflation, in character format} -\item{Author}{Author of the document on stagflation} -\item{Author_date}{Use this as a label for nodes} -\item{Year}{Year of publication of the document} -\item{Title}{Title of the document} -\item{Journal}{Journal of publication of the document (if an article)} +\item{source_id}{Identifier of the document on stagflation, in character format} +\item{source_author}{Author of the document on stagflation} +\item{source_label}{Use this as a label for nodes} +\item{source_year}{Year of publication of the document} +\item{source_title}{Title of the document} +\item{source_journal}{Journal of publication of the document (if an article)} } } \source{ diff --git a/man/Nodes_stagflation.Rd b/man/Nodes_stagflation.Rd index 0c44245..0a2ffef 100644 --- a/man/Nodes_stagflation.Rd +++ b/man/Nodes_stagflation.Rd @@ -5,15 +5,15 @@ \alias{Nodes_stagflation} \title{Articles and Books Explaining the 1970s US Stagflation.} \format{ -A data frame with 558 rows and 7 variables: +A data frame with 654 rows and 7 variables: \describe{ -\item{ItemID_Ref}{Identifier of the document} -\item{Author}{Author of the document} -\item{Author_date}{Use this as a label for nodes} -\item{Year}{Year of publication of the document} -\item{Title}{Title of the document} -\item{Journal}{Journal of publication of the document (if an article)} -\item{Type}{If "Stagflation", the document is listed as an explanation of the US stagflation. +\item{source_id}{Identifier of the document} +\item{source_author}{Author of the document} +\item{source_label}{Use this as a label for nodes} +\item{source_year}{Year of publication of the document} +\item{source_title}{Title of the document} +\item{source_journal}{Journal of publication of the document (if an article)} +\item{source_type}{If "Stagflation", the document is listed as an explanation of the US stagflation. If "Non-Stagflation", the document is cited by a document explaining the stagflation} } } diff --git a/man/Ref_stagflation.Rd b/man/Ref_stagflation.Rd index 2299363..aba643f 100644 --- a/man/Ref_stagflation.Rd +++ b/man/Ref_stagflation.Rd @@ -7,12 +7,12 @@ \format{ A data frame with 4416 rows and 6 variables: \describe{ -\item{Citing_ItemID_Ref}{Identifier of the citing document} -\item{ItemID_Ref}{Identifier of the cited document} -\item{Author}{Author of the cited document} -\item{Year}{Year of publication of the cited document} -\item{Title}{Title of the cited document} -\item{Journal}{Journal of publication of the cited document (if an article)} +\item{source_id}{Identifier of the citing document} +\item{target_id}{Identifier of the cited document} +\item{target_author}{Author of the cited document} +\item{target_year}{Year of publication of the cited document} +\item{target_title}{Title of the cited document} +\item{target_journal}{Journal of publication of the cited document (if an article)} } } \source{ diff --git a/man/add_clusters.Rd b/man/add_clusters.Rd index 3faa272..218acdc 100644 --- a/man/add_clusters.Rd +++ b/man/add_clusters.Rd @@ -105,7 +105,7 @@ for the edges, called \code{cluster_leiden_from}, \code{cluster_leiden_to} and \ The function also automatically calculates the percentage of total nodes that are gathered in each -cluster, in the column \code{size_com}. +cluster, in the column \verb{size_cluster_\{clustering_method\}}. To make plotting easier later, a zero is put before one-digit cluster identifier (cluster 5 becomes "05"; cluster 10 becomes "10"). Attributing a cluster identifier to edges @@ -115,18 +115,16 @@ or a different color from both nodes, if the nodes belong to different clusters. \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, diff --git a/man/add_node_roles.Rd b/man/add_node_roles.Rd index 3c1dc84..a72688c 100644 --- a/man/add_node_roles.Rd +++ b/man/add_node_roles.Rd @@ -45,18 +45,16 @@ The \code{z_threshold} parameter can be adjusted to change the sensitivity of hu \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, diff --git a/man/build_dynamic_networks.Rd b/man/build_dynamic_networks.Rd index 073c041..a987ea0 100644 --- a/man/build_dynamic_networks.Rd +++ b/man/build_dynamic_networks.Rd @@ -2,9 +2,7 @@ % Please edit documentation in R/build_dynamic_networks.R \name{build_dynamic_networks} \alias{build_dynamic_networks} -\alias{build_dynamic_networks2} -\alias{build_network} -\title{Creating One or Multiple Networks from a List of Nodes and Directed Edges} +\title{Build One or Multiple Networks from Bipartite Links} \usage{ build_dynamic_networks( nodes, @@ -13,27 +11,10 @@ build_dynamic_networks( target_id, time_variable = NULL, time_window = NULL, - cooccurrence_method = c("coupling_angle", "coupling_strength", "coupling_similarity"), - overlapping_window = FALSE, - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ..., - verbose = TRUE -) - -build_dynamic_networks2( - nodes, - directed_edges, - source_id, - target_id, - time_variable = NULL, - time_window = NULL, - backbone_method = c("structured", "statistical"), + projection_method = c("structured", "statistical"), model = c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol"), alpha = NULL, - coupling_measure = c("coupling_angle", "coupling_strength", "coupling_similarity"), + cooccurrence_method = c("coupling_angle", "coupling_strength", "coupling_similarity"), edges_threshold = 1, overlapping_window = FALSE, compute_size = FALSE, @@ -43,139 +24,132 @@ build_dynamic_networks2( backbone_args = list(), verbose = TRUE ) - -build_network( - nodes, - directed_edges, - source_id, - target_id, - cooccurrence_method = c("coupling_angle", "coupling_strength", "coupling_similarity"), - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ... -) } \arguments{ -\item{nodes}{The table with all the nodes and their metadata. For instance, if your nodes are -articles, this table is likely to contain the year of publication, the name of the authors, -the title of the article, etc... The table must have one row per node.} - -\item{directed_edges}{The table with of all the elements to which your nodes are connected. If your nodes are -articles, the \code{directed_edges} table can contain the list of the references cited -by these articles, the authors that have written these articles, or the affiliations -of the authors of these articles.} - -\item{source_id}{The quoted name of the column with the unique identifier of each node. For instance, -for a bibliographic coupling network, the id of your citing documents. It corresponds -to the \code{source} argument of \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork} -functions.} - -\item{target_id}{The quoted name of the column with the unique identifier of each element connected to the node (for -instance, the identifier of the reference cited by your node if the node is an article). -It corresponds to the \code{ref} argument of -\href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork} functions.} - -\item{time_variable}{The column with the temporal variable you want to use to build your windows for the -succession of networks. By default, \code{time_variable} is \code{NULL} and the function -will only build one network without taking into account any temporal variable.} - -\item{time_window}{The length of your network relatively of the unity of the \code{time_variable} column. If you -use a variable in years as \code{time_variable} and you set \code{time_window} at 5, the function -will build network on five year windows. By default, \code{time_window} is \code{NULL} and the -function will only build one network.} - -\item{cooccurrence_method}{Choose a cooccurrence method to build your indirect edges table. The function propose -three methods that depends on the \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork package} -and three methods that are implemented in it: -\itemize{ -\item the coupling angle measure (see \code{\link[biblionetwork:biblio_coupling]{biblionetwork::biblio_coupling()}} for documentation); -\item the coupling strength measure (\code{\link[biblionetwork:coupling_strength]{biblionetwork::coupling_strength()}}); -\item the coupling similarity measure (\code{\link[biblionetwork:coupling_similarity]{biblionetwork:: coupling_similarity()}}). -}} +\item{nodes}{Table of nodes and their metadata. One row per node. For example, a table +of articles with identifiers, authors, publication year, etc.} -\item{overlapping_window}{Set to \code{FALSE} by default. If set to \code{TRUE}, and if \code{time_variable} and \code{time_window} not -\code{NULL}, the function will create a succession of networks for moving time windows. The windows are -moving one unit per one unit of the \code{time_variable}. For instance, for years, if \code{time_window} -set to 5, it creates networks for successive time windows like 1970-1974, 1971-1975, 1972-1976, etc.} +\item{directed_edges}{Table of bipartite links between \code{source_id} nodes and +\code{target_id} entities (e.g., article -> reference, author -> paper).} -\item{edges_threshold}{Threshold value for building your edges. With a higher threshold, only the stronger links -will be kept. See the \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork package} -documentation and the \code{cooccurrence_method} parameter.} +\item{source_id}{Quoted name of the source-side node identifier.} -\item{compute_size}{Set to \code{FALSE} by default. If \code{TRUE}, the function uses the \code{directed_edges} data -to calculate how many directed edges a node receives (as a target). If \code{directed_edges} -is a table of direct citations, the functions calculates the number of time a node -is cited by the other nodes. You need to have the \code{target_id} in the \code{nodes} table -to make the link with the targetted nodes in the \code{directed_edges} table.} +\item{target_id}{Quoted name of the target-side identifier linked to each source node.} -\item{keep_singleton}{Set to \code{FALSE} by default. If \code{TRUE}, the function removes the nodes that have no -undirected edges, i.e. no cooccurrence with any other nodes. In graphical terms, -these nodes are alone in the network, with no link with other nodes.} +\item{time_variable}{Optional name of the column with a temporal variable (e.g., publication year).} -\item{filter_components}{Set to \code{TRUE} if you want to run \code{networkflow::filter_components()} -to filter the components of the network(s) and keep only the biggest component(s). If -you don't change the defaults parameters of \code{networkflow::filter_components()}, -it will keep only the main component.} +\item{time_window}{Optional size of the time window (in units of \code{time_variable}) to construct temporal networks.} -\item{...}{Additional arguments from \code{networkflow::filter_components()}.} +\item{projection_method}{method used to extract the network backbone. Choose between: +\itemize{ +\item \code{"structured"}: uses cooccurrence measures from the \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork} package; +\item \code{"statistical"}: uses statistical models from the \href{https://github.com/zpneal/backbone}{backbone} package. +Defaults to \code{"structured"}. The \code{"statistical"} method can be computationally slow on large networks. +}} -\item{verbose}{Set to \code{FALSE} if you don't want the function to display different sort of information.} +\item{model}{Statistical null model from \href{https://github.com/zpneal/backbone}{backbone}: +one of \code{"sdsm"}, \code{"fdsm"}, \code{"fixedfill"}, \code{"fixedrow"}, \code{"fixedcol"}. +Required if \code{projection_method = "statistical"}.} -\item{backbone_method}{Method used to extract the network backbone. Choose between: +\item{alpha}{Significance threshold for statistical backbone filtering. Required if +\code{projection_method = "statistical"}. Lower values keep fewer edges.} + +\item{cooccurrence_method}{For \code{projection_method = "structured"}, choose the coupling method: \itemize{ -\item \code{"structured"}: uses cooccurrence measures from the \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork} package; -\item \code{"statistical"}: uses statistical models from the \href{https://github.com/djmurphy533/backbone}{backbone} package. +\item \code{"coupling_angle"} +\item \code{"coupling_strength"}; +\item \code{"coupling_similarity"}. }} -\item{alpha}{Significance threshold for statistical backbone extraction. Required if -\code{backbone_method = "statistical"}.} +\item{edges_threshold}{Threshold used to filter weak edges in structured mode.} + +\item{overlapping_window}{Logical. If \code{TRUE}, builds networks using rolling time windows.} -\item{statistical_method}{For \code{backbone_method = "statistical"}, select the null model: one of -\code{"sdsm"}, \code{"fdsm"}, \code{"fixedfill"}, \code{"fixedfrow"}, \code{"fixedcol"}.} +\item{compute_size}{Logical. If \code{TRUE}, computes the number of incoming edges per node (e.g., citation count).} + +\item{keep_singleton}{Logical. If \code{FALSE}, removes nodes with no edges in the final network.} + +\item{filter_components}{Logical. If \code{TRUE}, keeps only the main component(s) using \code{networkflow::filter_components()}.} + +\item{...}{Additional arguments passed to \code{filter_components()}.} + +\item{backbone_args}{Optional list of additional arguments passed to the +backbone extraction call. If \code{backbone_args} includes \code{alpha} or \code{model}, +those values override function arguments.} + +\item{verbose}{Logical. If \code{TRUE}, displays progress messages.} } \value{ -If \code{time_window} is \code{NULL}, the function computes only -one network and return a tidygraph object built with \link[tidygraph:tbl_graph]{tbl_graph()}. -If \code{time_variable} and \code{time_window} are not \code{NULL}, the function returns a list -of tidygraph networks, for each time window. +\itemize{ +\item A single tidygraph object if \code{time_window} is \code{NULL}; +\item A list of tidygraph objects (one per time window) otherwise. +} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -\code{build_network()} creates a network from a table of nodes and its -directed edges. That is a special case of the more general \code{build_dynamic_networks()}. -This function creates one or several tibble graphs (built with -\href{https://tidygraph.data-imaginist.com/}{tidygraph}) from a table of nodes and its -directed edges. For instance, for bibliometric networks, you can give a list of -articles and the list of the references these articles cite. You can use it to -build a single network or multiple networks over different time windows. +\code{build_dynamic_networks()} builds one or several \code{tbl_graph} networks from a +node table (\code{source_id}) and a bipartite link table (\code{source_id} -> \code{target_id}). \code{build_network()} is a wrapper for a single network. + +It supports two backbone extraction methods: +\itemize{ +\item structured filtering using coupling/cooccurrence measures from +\href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork}; +\item statistical filtering using null models from +\href{https://github.com/zpneal/backbone}{backbone} \insertCite{neal2022}{networkflow}. +} + +The function can build a single network or multiple networks across time windows. } \details{ -\code{build_network()} has been added for convenience but it is just -a special case of the more general \code{build_dynamic_networks()}, with +The function uses bipartite links (\code{source_id} -> \code{target_id}) to produce +source-side networks. + +If \code{time_variable} and \code{time_window} are provided, it builds one network per +time window (rolling or non-overlapping). Otherwise it builds a single network. + +\code{projection_method = "structured"} applies coupling/cooccurrence filtering. +\code{projection_method = "statistical"} applies a statistical backbone model. } \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation -temporal_networks <- build_dynamic_networks(nodes = nodes, +# Structured backbone (cooccurrence) +net_structured <- build_dynamic_networks( +nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", -cooccurrence_method = "coupling_similarity", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", time_window = 20, -edges_threshold = 1, -overlapping_window = TRUE) +projection_method = "structured", +cooccurrence_method = "coupling_similarity", +edges_threshold = 1 +) -temporal_networks[[1]] +# Statistical backbone (backbone package) +net_statistical <- build_dynamic_networks( +nodes = nodes, +directed_edges = references, +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", +time_window = 20, +projection_method = "statistical", +model = "sdsm", +alpha = 0.05, +backbone_args = list(mtc = "holm") +) } +\references{ +\insertAllCited{} +} +\seealso{ +\code{\link[biblionetwork:biblio_coupling]{biblionetwork::biblio_coupling()}}, \code{\link[backbone:backbone]{backbone::backbone()}} +} diff --git a/man/build_dynamic_networks2.Rd b/man/build_dynamic_networks2.Rd deleted file mode 100644 index 8b5324a..0000000 --- a/man/build_dynamic_networks2.Rd +++ /dev/null @@ -1,160 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/build_dynamic_networks2.R -\name{build_dynamic_networks2} -\alias{build_dynamic_networks2} -\title{Creating One or Multiple Networks Using Structured or Statistical Backbone Extraction} -\usage{ -build_dynamic_networks2( - nodes, - directed_edges, - source_id, - target_id, - time_variable = NULL, - time_window = NULL, - backbone_method = c("structured", "statistical"), - model = c("sdsm", "fdsm", "fixedfill", "fixedrow", "fixedcol"), - alpha = NULL, - coupling_measure = c("coupling_angle", "coupling_strength", "coupling_similarity"), - edges_threshold = 1, - overlapping_window = FALSE, - compute_size = FALSE, - keep_singleton = FALSE, - filter_components = FALSE, - ..., - backbone_args = list(), - verbose = TRUE -) -} -\arguments{ -\item{nodes}{Table of nodes and their metadata. One row per node. For example, a table -of articles with identifiers, authors, publication year, etc.} - -\item{directed_edges}{Table of edges representing the links between nodes and associated entities -(e.g., references, authors, affiliations).} - -\item{source_id}{Quoted name of the column giving the unique identifier of each node.} - -\item{target_id}{Quoted name of the column giving the identifier of the element linked to each node.} - -\item{time_variable}{Optional name of the column with a temporal variable (e.g., publication year).} - -\item{time_window}{Optional size of the time window (in units of \code{time_variable}) to construct temporal networks.} - -\item{backbone_method}{Method used to extract the network backbone. Choose between: -\itemize{ -\item \code{"structured"}: uses cooccurrence measures from the \href{https://agoutsmedt.github.io/biblionetwork/}{biblionetwork} package; -\item \code{"statistical"}: uses statistical models from the \href{https://github.com/djmurphy533/backbone}{backbone} package. -Defaults to \code{"structured"}. -}} - -\item{model}{Null model used by the \href{https://github.com/zpneal/backbone}{backbone} -package: one of \code{"sdsm"}, \code{"fdsm"}, \code{"fixedfill"}, \code{"fixedrow"}, \code{"fixedcol"}. Required if -\code{backbone_method = "statistical"}. These correspond to model names in \code{backbone} and are passed -through to the selected backbone function.} - -\item{alpha}{Significance threshold for statistical backbone extraction. Required if -\code{backbone_method = "statistical"}. Lower values keep fewer edges (stricter filtering).} - -\item{coupling_measure}{For \code{backbone_method = "structured"}, choose the cooccurrence method: -\itemize{ -\item \code{"coupling_angle"} (biblio_coupling); -\item \code{"coupling_strength"}; -\item \code{"coupling_similarity"}. -}} - -\item{edges_threshold}{Threshold for edge weight filtering in structured methods.} - -\item{overlapping_window}{Logical. If \code{TRUE}, builds networks using rolling time windows.} - -\item{compute_size}{Logical. If \code{TRUE}, computes the number of incoming edges per node (e.g., citation count).} - -\item{keep_singleton}{Logical. If \code{FALSE}, removes nodes with no edges in the final network.} - -\item{filter_components}{Logical. If \code{TRUE}, keeps only the main component(s) using \code{networkflow::filter_components()}.} - -\item{...}{Additional arguments passed to \code{filter_components()}.} - -\item{backbone_args}{Optional list of additional arguments passed to -\code{\link[backbone:backbone_from_projection]{backbone::backbone_from_projection()}}. Use this to set parameters like \code{mtc}, -\code{signed}, \code{missing_as_zero}, or \code{trials}. If \code{backbone_args} includes \code{alpha} or -\code{model}, those values override the corresponding function arguments.} - -\item{verbose}{Logical. If \code{TRUE}, displays progress messages.} -} -\value{ -\itemize{ -\item A single tidygraph object if \code{time_window} is \code{NULL}; -\item A list of tidygraph objects (one per time window) otherwise. -} -} -\description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} - -\code{build_dynamic_networks2()} builds one or several networks (as tidygraph objects) -from a table of nodes and directed edges, with support for both structured cooccurrence -methods and statistical backbone extraction using the \href{https://github.com/zpneal/backbone}{backbone} -package \insertCite{neal2022}{networkflow}. -The function is useful for constructing bibliometric or affiliation networks across -static or dynamic time windows. -} -\details{ -\code{build_dynamic_networks2()} generalizes \code{build_dynamic_networks()} by adding support for -statistical backbone extraction using null models from the \code{backbone} package -\insertCite{neal2022}{networkflow}. The cooccurence methods used in -\code{build_dynamic_networks()} can be viewed as deterministic (structured) methods to extract -the network backbone. The backbone is defined as the significant edges in the network. - -As with \code{build_dynamic_networks()}, the function constructs networks for each time window. If \code{time_variable} and \code{time_window} are defined, the function constructs networks -for each time window (sliding or non-overlapping). Otherwise, it builds a single static network. - -If \code{backbone_method = "structured"}, cooccurrence edges are computed using bibliometric coupling -techniques. The term structured refers to deterministic methods based on thresholding cooccurrence measures. -If \code{backbone_method = "statistical"}, the function applies a \code{backbone} null model to the -edgelist for each time window and keeps only statistically significant edges at the chosen \code{alpha}. -The model is selected via \code{model} and follows \code{backbone}'s nomenclature: \code{"sdsm"}, \code{"fdsm"}, -\code{"fixedfill"}, \code{"fixedrow"}, or \code{"fixedcol"}. Only these models are currently supported. -} -\examples{ -library(networkflow) - -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") - -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) - -# Structured backbone (cooccurrence) -net_structured <- build_dynamic_networks2( -nodes = nodes, -directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", -time_window = 20, -backbone_method = "structured", -coupling_measure = "coupling_similarity", -edges_threshold = 1 -) - -# Statistical backbone (backbone package) -net_statistical <- build_dynamic_networks2( -nodes = nodes, -directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", -time_window = 20, -backbone_method = "statistical", -model = "sdsm", -alpha = 0.05, -backbone_args = list(mtc = "holm") -) - -} -\references{ -\insertAllCited{} -} -\seealso{ -\code{\link[biblionetwork:biblio_coupling]{biblionetwork::biblio_coupling()}}, \code{\link[backbone:backbone_from_projection]{backbone::backbone_from_projection()}} -} diff --git a/man/build_network.Rd b/man/build_network.Rd new file mode 100644 index 0000000..30e3096 --- /dev/null +++ b/man/build_network.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/build_dynamic_networks.R +\name{build_network} +\alias{build_network} +\title{Build a single network} +\usage{ +build_network( + nodes, + directed_edges, + source_id, + target_id, + projection_method, + cooccurrence_method = c("coupling_angle", "coupling_strength", "coupling_similarity"), + edges_threshold = 1, + compute_size = FALSE, + keep_singleton = FALSE, + filter_components = FALSE, + ... +) +} +\arguments{ +\item{nodes}{Table of nodes and their metadata. One row per node. For example, a table +of articles with identifiers, authors, publication year, etc.} + +\item{directed_edges}{Table of bipartite links between \code{source_id} nodes and +\code{target_id} entities (e.g., article -> reference, author -> paper).} + +\item{source_id}{Quoted name of the source-side node identifier.} + +\item{target_id}{Quoted name of the target-side identifier linked to each source node.} + +\item{projection_method}{Method used to build the single network. Must be +one of \code{"structured"} or \code{"statistical"}.} + +\item{cooccurrence_method}{Cooccurrence method used by the structured workflow.} + +\item{edges_threshold}{Threshold used to filter weak edges in structured mode.} + +\item{compute_size}{Logical. If \code{TRUE}, computes the number of incoming edges per node (e.g., citation count).} + +\item{keep_singleton}{Logical. If \code{FALSE}, removes nodes with no edges in the final network.} + +\item{filter_components}{Logical. If \code{TRUE}, keeps only the main component(s) using \code{networkflow::filter_components()}.} + +\item{...}{Additional arguments passed to \code{filter_components()}.} +} +\description{ +Convenience wrapper around \code{\link[=build_dynamic_networks]{build_dynamic_networks()}} for a single network. +} diff --git a/man/color_networks.Rd b/man/color_networks.Rd index 16f532a..0250929 100644 --- a/man/color_networks.Rd +++ b/man/color_networks.Rd @@ -67,18 +67,16 @@ the colors of the two palettes will be recycled. \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, diff --git a/man/dynamic_network_cooccurrence.Rd b/man/dynamic_network_cooccurrence.Rd index 8abe218..2ff362a 100644 --- a/man/dynamic_network_cooccurrence.Rd +++ b/man/dynamic_network_cooccurrence.Rd @@ -91,18 +91,16 @@ articles and the list of the references these articles cite. You can use it to build a single network or multiple networks over different time windows. } \examples{ -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> +dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, directed_edges = references, -source_column = "ID_Art", -target_column = "ItemID_Ref", -time_variable = "Year", +source_column = "source_id", +target_column = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = NULL, edges_threshold = 1, diff --git a/man/extract_tfidf.Rd b/man/extract_tfidf.Rd index 95c5448..a889e79 100644 --- a/man/extract_tfidf.Rd +++ b/man/extract_tfidf.Rd @@ -103,18 +103,16 @@ The terms which occur only once are removed to avoid too rare terms to appear at the top of your grouping variables. } \examples{ -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 10, edges_threshold = 1, @@ -128,10 +126,10 @@ clustering_method = "leiden") library(stopwords) tfidf <- extract_tfidf(temporal_networks, n_gram = 4, -text_columns = "Title", +text_columns = "source_title", grouping_columns = "cluster_leiden", grouping_across_list = TRUE, -clean_word_method = "lemmatise") +clean_word_method = "lemmatize") tfidf[[1]] diff --git a/man/intertemporal_cluster_naming.Rd b/man/intertemporal_cluster_naming.Rd index ed2c1d0..164e60f 100644 --- a/man/intertemporal_cluster_naming.Rd +++ b/man/intertemporal_cluster_naming.Rd @@ -63,18 +63,16 @@ library(biblionetwork) library(magrittr) library(tidygraph) -nodes <- Nodes_stagflation \%>\% -dplyr::rename(ID_Art = ItemID_Ref) \%>\% -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation \%>\% +dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation \%>\% -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- dynamic_network_cooccurrence(nodes = nodes, directed_edges = references, -source_column = "ID_Art", -target_column = "ItemID_Ref", -time_variable = "Year", +source_column = "source_id", +target_column = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 15, edges_threshold = 1, @@ -88,7 +86,7 @@ temporal_networks <- lapply(temporal_networks, intertemporal_cluster_naming(temporal_networks, cluster_column = "clusters", -node_key = "ID_Art", +node_key = "source_id", threshold_similarity = 0.51, similarity_type = "partial") diff --git a/man/launch_network_app.Rd b/man/launch_network_app.Rd index 33f3649..be7fe87 100644 --- a/man/launch_network_app.Rd +++ b/man/launch_network_app.Rd @@ -53,18 +53,18 @@ If the graph does not contain a layout (columns \code{x} and \code{y}) the funct library(networkflow) library(dplyr) -nodes <- Nodes_stagflation |> - dplyr::filter(Type == "Stagflation") |> - dplyr::rename(ID_Art = ItemID_Ref) +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") |> + dplyr::mutate(source_id = as.character(source_id)) -references <- Ref_stagflation |> - dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation g <- build_network( nodes = nodes, directed_edges = references, - source_id = "ID_Art", - target_id = "ItemID_Ref", + source_id = "source_id", + target_id = "target_id", + projection_method = "structured", cooccurrence_method = "coupling_similarity", edges_threshold = 1, compute_size = FALSE, @@ -81,10 +81,10 @@ g <- add_clusters( launch_network_app( graph_tbl = g, cluster_id = "cluster_leiden", - cluster_information = c("Author", "Title", "Year", "Journal"), + cluster_information = c("source_author", "source_title", "source_year", "source_journal"), cluster_tooltip = "Cluster", - node_id = "ID_Art", - node_tooltip = "Author_date", + node_id = "source_id", + node_tooltip = "source_label", node_size = NULL, color = NULL, layout = "kk" @@ -95,9 +95,9 @@ launch_network_app( g_list <- build_dynamic_networks( nodes = nodes, directed_edges = references, - source_id = "ID_Art", - target_id = "ItemID_Ref", - time_variable = "Year", + source_id = "source_id", + target_id = "target_id", + time_variable = "source_year", time_window = 20, cooccurrence_method = "coupling_similarity", edges_threshold = 1, @@ -116,9 +116,9 @@ g_list <- add_clusters( launch_network_app( graph_tbl = g_list, cluster_id = "cluster_leiden", - cluster_information = c("Author", "Title", "Year", "Journal"), - node_id = "ID_Art", - node_tooltip = "Author_date", + cluster_information = c("source_author", "source_title", "source_year", "source_journal"), + node_id = "source_id", + node_tooltip = "source_label", node_size = NULL, color = NULL, layout = "kk" diff --git a/man/layout_networks.Rd b/man/layout_networks.Rd index f1176b4..c1f105b 100644 --- a/man/layout_networks.Rd +++ b/man/layout_networks.Rd @@ -61,18 +61,16 @@ if the layout used allows a parameter called \code{coord}. \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, @@ -80,7 +78,7 @@ overlapping_window = TRUE, filter_components = TRUE) temporal_networks <- layout_networks(temporal_networks, -node_id = "ID_Art", +node_id = "source_id", layout = "fr", compute_dynamic_coordinates = TRUE) diff --git a/man/merge_dynamic_clusters.Rd b/man/merge_dynamic_clusters.Rd index b545edb..360d02c 100644 --- a/man/merge_dynamic_clusters.Rd +++ b/man/merge_dynamic_clusters.Rd @@ -66,18 +66,16 @@ the user: \code{threshold_similarity}, \code{cluster_colum} and \code{similarity \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 10, edges_threshold = 1, @@ -90,7 +88,7 @@ clustering_method = "leiden") temporal_networks <- merge_dynamic_clusters(temporal_networks, cluster_id = "cluster_leiden", -node_id = "ID_Art", +node_id = "source_id", threshold_similarity = 0.51, similarity_type = "partial") diff --git a/man/name_clusters.Rd b/man/name_clusters.Rd index 4253e44..b6ef9a0 100644 --- a/man/name_clusters.Rd +++ b/man/name_clusters.Rd @@ -97,18 +97,16 @@ tibble graphs will share the same name. \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, @@ -127,7 +125,7 @@ temporal_networks_with_names <- name_clusters(graphs = temporal_networks, method = "tidygraph_functions", name_merged_clusters = FALSE, cluster_id = "cluster_leiden", -label_columns = c("Author", "Year"), +label_columns = c("source_author", "source_year"), tidygraph_function = tidygraph::centrality_pagerank()) temporal_networks_with_names[[1]] @@ -136,7 +134,7 @@ temporal_networks_with_names[[1]] temporal_networks <- merge_dynamic_clusters(temporal_networks, cluster_id = "cluster_leiden", -node_id = "ID_Art", +node_id = "source_id", threshold_similarity = 0.51, similarity_type = "partial") @@ -144,9 +142,9 @@ temporal_networks_with_names <- name_clusters(graphs = temporal_networks, method = "tf-idf", name_merged_clusters = TRUE, cluster_id = "dynamic_cluster_leiden", -text_columns = "Title", +text_columns = "source_title", nb_terms_label = 5, -clean_word_method = "lemmatise") +clean_word_method = "lemmatize") temporal_networks_with_names[[1]] diff --git a/man/networkflow-package.Rd b/man/networkflow-package.Rd index 46d40bf..2df59f1 100644 --- a/man/networkflow-package.Rd +++ b/man/networkflow-package.Rd @@ -6,7 +6,7 @@ \alias{networkflow-package} \title{networkflow: Functions For A Workflow To Manipulate Networks} \description{ -This package proposes a series of function to make it easier and quicker to work on networks. It mainly targets working on bibliometric networks (see the [biblionetwork](https://github.com/agoutsmedt/biblionetwork) package for creating such networks). This package heavily relies on [igraph](https://igraph.org/r/) and [tidygraph](https://tidygraph.data-imaginist.com/index.html), and aims at producing ready-made networks for projecting them using [ggraph](https://ggraph.data-imaginist.com/). This package does not invent nothing new, properly speaking, but it allows the users to follow more quickly and easily the main steps of network manipulation, from creating the graph to projecting it. It is inspired by what could be done with [GEPHI](https://gephi.org/): the package allows the use of the Leiden community detection algorithm, as well as of the Force Atlas 2 layout, both being unavailable in igraph (and so in tidygraph). +Provides a workflow to build, analyze, and visualize projected networks from tabular data. The package supports dynamic analysis across time windows, including cluster detection and cross-period cluster matching. It also covers network construction, interpretation, static plotting, and interactive exploration through a 'shiny' app. Although designed for projected networks (e.g., article -> reference), it can be used more generally with 'tbl_graph' objects. } \seealso{ Useful links: @@ -23,6 +23,7 @@ Useful links: Authors: \itemize{ \item Alexandre Truc \email{alexandre.truc77@gmail.com} (\href{https://orcid.org/0000-0002-1328-7819}{ORCID}) + \item Thomas Delcey (\href{https://orcid.org/0000-0003-0546-1474}{ORCID}) } } diff --git a/man/networks_to_alluv.Rd b/man/networks_to_alluv.Rd index d7594a5..014004a 100644 --- a/man/networks_to_alluv.Rd +++ b/man/networks_to_alluv.Rd @@ -56,18 +56,16 @@ This function creates a data.frame that can be easily plotted with ggalluvial fr \examples{ library(networkflow) -nodes <- Nodes_stagflation |> -dplyr::rename(ID_Art = ItemID_Ref) |> -dplyr::filter(Type == "Stagflation") +nodes <- networkflow::Nodes_stagflation |> + dplyr::filter(source_type == "Stagflation") -references <- Ref_stagflation |> -dplyr::rename(ID_Art = Citing_ItemID_Ref) +references <- networkflow::Ref_stagflation temporal_networks <- build_dynamic_networks(nodes = nodes, directed_edges = references, -source_id = "ID_Art", -target_id = "ItemID_Ref", -time_variable = "Year", +source_id = "source_id", +target_id = "target_id", +time_variable = "source_year", cooccurrence_method = "coupling_similarity", time_window = 20, edges_threshold = 1, @@ -82,7 +80,7 @@ verbose = FALSE) temporal_networks <- merge_dynamic_clusters(temporal_networks, cluster_id = "cluster_leiden", -node_id = "ID_Art", +node_id = "source_id", threshold_similarity = 0.51, similarity_type = "partial") @@ -90,9 +88,9 @@ temporal_networks <- name_clusters(graphs = temporal_networks, method = "tf-idf", name_merged_clusters = TRUE, cluster_id = "dynamic_cluster_leiden", -text_columns = "Title", +text_columns = "source_title", nb_terms_label = 5, -clean_word_method = "lemmatise") +clean_word_method = "lemmatize") temporal_networks <- color_networks(graphs = temporal_networks, column_to_color = "dynamic_cluster_leiden", @@ -100,7 +98,7 @@ color = NULL) alluv_dt <- networks_to_alluv(temporal_networks, intertemporal_cluster_column = "dynamic_cluster_leiden", -node_id = "ID_Art") +node_id = "source_id") alluv_dt[1:5] diff --git a/vignettes/.gitignore b/vignettes/.gitignore index 097b241..47018d6 100644 --- a/vignettes/.gitignore +++ b/vignettes/.gitignore @@ -1,2 +1,5 @@ *.html *.R + +/.quarto/ +**/*.quarto_ipynb diff --git a/vignettes/exploring_dynamic_networks.Rmd b/vignettes/exploring_dynamic_networks.Rmd deleted file mode 100644 index 3b54133..0000000 --- a/vignettes/exploring_dynamic_networks.Rmd +++ /dev/null @@ -1,142 +0,0 @@ ---- -title: "Exploring dynamic networks" -author: "Aurélien Goutsmedt and Alexandre Truc" -description: "Introduction to the uses of the networkflow package for temporal networks" -output: - rmarkdown::html_vignette: - toc: true -vignette: > - %\VignetteIndexEntry{Exploring dynamic networks} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - - - -This vignette introduces you to some functions of the package with the [data integrated][Incorporated data] -in the package. Here, we are interested to the exploration of dynamic networks. - -# Building your list of networks - -```{r setup} -library(networkflow) -library(magrittr) -library(dplyr) -library(tidygraph) -``` - -```{r} -nodes <- Nodes_stagflation %>% - dplyr::rename(ID_Art = ItemID_Ref) %>% - dplyr::filter(Type == "Stagflation") - -references <- Ref_stagflation %>% - dplyr::rename(ID_Art = Citing_ItemID_Ref) -``` - - -```{r} -single_network <- dynamic_network_cooccurrence(nodes = nodes, - directed_edges = references, - source_column = "ID_Art", - target_column = "ItemID_Ref", - time_variable = NULL, - cooccurrence_method = "coupling_similarity", - time_window = NULL, - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - overlapping_window = TRUE) -``` - -```{r} -network_list <- dynamic_network_cooccurrence(nodes = nodes, - directed_edges = references, - source_column = "ID_Art", - target_column = "ItemID_Ref", - time_variable = "Year", - cooccurrence_method = "coupling_similarity", - time_window = 15, - edges_threshold = 1, - compute_size = FALSE, - keep_singleton = FALSE, - overlapping_window = TRUE) - -network_list[[1]] -``` - -# Clustering and intertemporal naming - -```{r} -network_list <- lapply(network_list, - function(tbl) tbl %N>% mutate(clusters = group_louvain())) - -``` - -```{r} -network_list <- intertemporal_cluster_naming(list_graph = network_list, - cluster_column = "clusters", - node_key = "ID_Art", - threshold_similarity = 0.5001, - similarity_type = "partial") - -network_list[[1]] -``` - -# Building Alluvial - -```{r, eval = FALSE, fig.dim=c(10,8)} -library(ggplot2) -library(ggalluvial) - -alluv_dt <- networks_to_alluv(list_graph = network_list, - intertemporal_cluster_column = "intertemporal_name", - node_key = "ID_Art", - summary_cl_stats = FALSE) - -alluv_dt <- minimize_crossing_alluvial(alluv_dt = alluv_dt, - node_key = "ID_Art") -alluv_dt[,y_alluv:=1/.N, Window] - -ggplot(alluv_dt, aes(x = Window, y= y_alluv, stratum = intertemporal_name, alluvium = ID_Art, fill = intertemporal_name, label = intertemporal_name)) + - geom_stratum(alpha =1, size=1/12) + - geom_flow() + - theme(legend.position = "none") + - theme_minimal() + - theme(plot.background = element_rect(fill = 'white', colour = NA)) + - ggtitle("") -``` - -# exploring tf-idf - -```{r, eval=FALSE} -corpus <- merge(alluv_dt, - nodes, - by = "ID_Art", - all.x = TRUE) - -tf_idf <- extract_tfidf(data = corpus, - text_columns = "Title", - grouping_columns = "intertemporal_name", - n_gram = 3L, - stopwords = NULL, - stopwords_type = "smart", - clean_word_method = "lemmatize", - ngrams_filter = 2) - -tf_idf %>% - group_by(document) %>% - slice_max(order_by = tf_idf, n = 1, with_ties = FALSE) %>% - ungroup() %>% - arrange(intertemporal_name) %>% - select(-document) - -``` - diff --git a/vignettes/networkflow_presentation.Rmd b/vignettes/networkflow_presentation.Rmd new file mode 100644 index 0000000..54c30cd --- /dev/null +++ b/vignettes/networkflow_presentation.Rmd @@ -0,0 +1,627 @@ +--- +title: "Presentation of networkflow" +author: "" +description: "" +output: + rmarkdown::html_vignette: + toc: true +vignette: > + %\VignetteIndexEntry{Presentation of networkflow} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +# Introduction + +## Overview + +`networkflow` provides a complete workflow to build, structure, and explore networks from tabular data. + +Its key feature is a built-in dynamic analysis workflow: the package can build networks across time windows, detect clusters in each window, and link clusters across periods to track their evolution. + +More broadly, `networkflow` supports the full analysis pipeline, from network construction to interpretation and visualization, including clustering, layout and color preparation, static plotting, and interactive exploration with a Shiny app. + +The package was developed with projected networks in mind (for example, article -> reference), but it can also be used more generally once data are represented as `tbl_graph` objects. + +## What this package does + +The package is organized in three main steps: + +1. create networks (static or dynamic) from tabular data; +2. detect and harmonize clusters across time windows; +3. prepare visualization and exploration outputs (layout, colors, labels, plotting, Shiny app). + + +## Typical workflow + +A typical workflow is: + +1. prepare `nodes` and `directed_edges` tables; +2. build the network with `build_network()` (or `build_dynamic_networks()` for temporal analyses); +3. detect clusters with `add_clusters()`; +4. prepare plotting attributes (`layout_networks()`, `color_networks()`); +5. inspect and interpret results with plots and `launch_network_app()`. + +# Data Requirements + +## Network objects: `tbl_graph` + +A **`tbl_graph`** is the core network object in `networkflow`. + +It comes from `tidygraph` and stores: + +1. a node table (attributes of entities); +2. an edge table (connections between entities). + +Most functions in this package take a `tbl_graph` (or a list of `tbl_graph`) as input. In practice, `build_network()` and `build_dynamic_networks()` are the main entry points that create these objects from tabular data. + +`networkflow` expects tabular inputs with explicit identifiers: + +1. `nodes`: one row per source entity (for example, one row per article), with a unique ID used as `source_id`; +2. `directed_edges`: links from `source_id` to `target_id` (for example, article -> reference, author -> paper); +3. `time_variable`: required only for dynamic analyses with `build_dynamic_networks()`. + + +## Input of `build_network()` and `build_dynamic_networks()` + +`build_network()` and `build_dynamic_networks()` are the main entry points to create `tbl_graph` objects in the package. They start from a bipartite relation (`source_id` -> `target_id`) and produce a one-mode weighted network on `source_id` entities. The bipartite relation is a table of directed edges from source to target entities (for example, article -> reference, author -> paper). After projection, the result is a one-mode network. + +If your data is already one-mode (for example, author -> author), you can build a `tbl_graph` directly and use downstream functions for clustering, layout, plotting, and exploration. Typical downstream functions in this case are `add_clusters()`, `layout_networks()`, `color_networks()`, and `launch_network_app()`. + +# Step 1: Creating networks + +Functions used: + +- `build_dynamic_networks()` +- `build_network()` +- `filter_components()` + +This step creates one static network (`tbl_graph`) or a list of temporal networks +(`list` of `tbl_graph`) from bipartite links (`source_id -> target_id`). +`build_network()` is the single-network wrapper around `build_dynamic_networks()`. + +### `build_network()` and `build_dynamic_networks()` + + +`build_dynamic_networks()` builds one network or a list of time-window networks if the user provides a temporal variable. `build_network()` is the wrapper for one network of `build_dynamic_networks(time_variable = NULL)`. `build_dynamic_networks()` supports two different filtering strategies: + +`build_dynamic_networks()` takes as input a bipartite relation and projects it into a one-mode network. It supports two different filtering strategies for edge retention after projection: + +1. a structured strategy, which defines edge strength using measures derived from co-occurrence intensity; +2. a statistical strategy, which defines a null model of random co-occurrence and keeps edges based on statistical significance. + +In short, the first approach defines and filters by observed tie strength, while the second defines and filters by statistical significance. The structured method is generally more computationally efficient, while the statistical method provides a more rigorous filter for connections beyond random chance. For example, if `source_id` is article and `target_id` is reference, the structured method will keep article pairs with strong co-citation or bibliographic coupling, while the statistical method will keep article pairs whose co-citation or bibliographic coupling is significantly stronger than expected under a random model. + +Parameters common to both methods: + +- `nodes`: table with one row per source entity defined by `source_id`. +- `directed_edges`: table with directed edges from `source_id` to `target_id`. +- `source_id`, `target_id`: identifier columns used for projection. +- `projection_method`: `"structured"` or `"statistical"`. +- `compute_size`: if `TRUE`, computes `node_size`. +- `keep_singleton`: if `FALSE`, removes isolated nodes. + +Structured-only parameters (`projection_method = "structured"`) + +- uses cooccurrence/coupling measures from the `biblionetwork` package. +- `cooccurrence_method`: `"coupling_angle"`, `"coupling_strength"`, `"coupling_similarity"`. +- `edges_threshold`: minimum edge strength retained. + + +Statistical-only parameters (`projection_method = "statistical"`) + +- uses statistical backbone extraction (`backbone` package). +- `model`: `"sdsm"`, `"fdsm"`, `"fixedfill"`, `"fixedrow"`, `"fixedcol"`. +- `alpha`: significance threshold for edge retention. +- `backbone_args`: additional arguments passed to backbone routines. + +Dynamic-only parameters (`build_dynamic_networks()`): + +- `time_variable`: temporal column in `nodes` (for example publication year). +- `time_window`: width of each window. +- `overlapping_window`: rolling windows (`TRUE`) or disjoint windows (`FALSE`). In the first case, partition is done by rolling the time window by one unit (for example, 1990-2009, 1991-2010, etc.). In the second case, partition is done by fixed intervals (for example, 1990-1999, 2000-2009, etc.). + +The main output of these functions is a `tbl_graph` (or a list of `tbl_graph` for dynamic analyses). If `projection_method = "structured"`, the output edges are weighted by the selected cooccurrence/coupling measure. If `projection_method = "statistical"`, the output edges are unweighted and retained based on statistical significance. + +Examples: + +```{r static-build-setup} +library(networkflow) + +nodes <- subset(Nodes_stagflation, source_type == "Stagflation") + +references <- Ref_stagflation +``` + +```{r static-build-network} +g_static <- build_network( + nodes = nodes, + directed_edges = references, + source_id = "source_id", + target_id = "target_id", + projection_method = "structured", + cooccurrence_method = "coupling_similarity", + edges_threshold = 1, + compute_size = FALSE, + keep_singleton = FALSE +) +``` + +```{r dynamic-build-network-structured, eval = FALSE} +g_dynamic <- build_dynamic_networks( + nodes = nodes, + directed_edges = references, + source_id = "source_id", + target_id = "target_id", + time_variable = "source_year", + time_window = 20, + projection_method = "structured", + cooccurrence_method = "coupling_similarity", + edges_threshold = 1, + overlapping_window = TRUE, + compute_size = FALSE, + keep_singleton = FALSE +) +``` + +```{r dynamic-build-network-statistical, eval = FALSE} +g_dynamic_stat <- build_dynamic_networks( + nodes = nodes, + directed_edges = references, + source_id = "source_id", + target_id = "target_id", + time_variable = "source_year", + time_window = 20, + projection_method = "statistical", + model = "sdsm", + alpha = 0.05, + overlapping_window = TRUE, + compute_size = FALSE, + keep_singleton = FALSE +) +``` + +### `filter_components()` + +Use `filter_components()` to keep the main connected component(s): + +- `nb_components`: number of largest components to keep. +- `threshold_alert`: warning threshold when a removed component is still large. +- `keep_component_columns`: keep or remove helper columns on component IDs and sizes. + +```{r static-filter-components, eval = FALSE} +g_static <- filter_components(g_static, nb_components = 1) +``` + + +# Step 2: Clustering + +Functions used: + +- `add_clusters()` +- `merge_dynamic_clusters()` +- `name_clusters()` +- `add_node_roles()` +- `extract_tfidf()` + +### `add_clusters()` + +Run community detection on a static or dynamic network. The function is a wrapper around `tidygraph::group_graph()`. It also supports the `igraph` implementation of the Leiden algorithm, which is the default method. + +Main parameters: + +- `clustering_method`: the clustering algorithm to use. +- `weights`: edge weight column usage. +- `objective_function`, `resolution`, `n_iterations`: Leiden controls. +- `seed`: reproducibility for stochastic algorithms. + +The output is a `tbl_graph` (or a list of `tbl_graph`) with new columns: +- node column `cluster_{method}`. +- edge columns `cluster_{method}_from`, `cluster_{method}_to`, `cluster_{method}`. +- node column `size_cluster_{method}` with cluster shares. + +Example: + +```{r static-add-clusters-leiden} +g_static <- add_clusters( + graphs = g_static, + clustering_method = "leiden", + objective_function = "modularity", + resolution = 1, + n_iterations = 1000, + seed = 123 +) +``` + +```{r dynamic-add-clusters-leiden, eval = FALSE} +g_dynamic <- add_clusters( + graphs = g_dynamic, + clustering_method = "leiden", + objective_function = "modularity", + resolution = 1, + n_iterations = 1000, + seed = 123 +) +``` + +### `merge_dynamic_clusters()`(dynamic only) + +`add_clusters()` runs independently on each time window, so cluster IDs are not directly comparable across windows. `merge_dynamic_clusters()` links clusters from adjacent windows when node overlap is high enough, and assigns stable intertemporal IDs. + +Input requirements: + +- `list_graph` must be a list of at least two `tbl_graph`. +- the list order must be chronological (oldest to most recent window). + +Main parameters: + +- `cluster_id`: input cluster column (for example `cluster_leiden`). +- `node_id`: stable node identifier across windows. +- `threshold_similarity`: matching threshold in `(0.5, 1]`. +- `similarity_type`: `"complete"` or `"partial"`. + +`similarity_type` controls how overlap is computed: + +- `"complete"`: the overlap share is computed over all nodes in the compared clusters, including entries that exist only in one window. This is stricter when network size changes over time. +- `"partial"`: the overlap share is computed only on nodes present in both adjacent windows. This is often preferable when many new nodes enter over time. + +Output: + +- new node column `dynamic_{cluster_id}` (for example `dynamic_cluster_leiden`). The dynamic cluster IDs are assigned by propagation: it starts by assigning unique IDs to clusters in the first time window, then propagates those IDs to later windows when a cluster match passes the similarity threshold; otherwise, a new dynamic ID is created. +- corresponding edge columns `dynamic_{cluster_id}_from`, `dynamic_{cluster_id}_to`, and `dynamic_{cluster_id}`. + +```{r dynamic-merge-clusters, eval = FALSE} +g_dynamic <- merge_dynamic_clusters( + list_graph = g_dynamic, + cluster_id = "cluster_leiden", + node_id = "source_id", + threshold_similarity = 0.51, + similarity_type = "partial" +) +``` + +### `name_clusters()` + +Cluster IDs are not very informative in themselves. `name_clusters()` helps assign readable labels to clusters based on their content. The labels are not meant to be definitive cluster names, but rather a quick way to get a sense of cluster content. The function supports three methods: + +- `method = "tf-idf"`: labels clusters with the most distinctive terms extracted from a `text_columns`. This is usually the best default for thematic interpretation. +- `method = "given_column"`: selects, within each cluster, the node with the + highest value in `order_by`, then builds the label from `label_columns` of + that node. Typically, you can use this method to label clusters with the title of a representative article (for example the most cited one). +- `method = "tidygraph_functions"`: computes a centrality measure with + `tidygraph_function`, selects the most central node per cluster, then builds + the label from `label_columns`. + +Main parameters: + +- `method`: `"tidygraph_functions"`, `"given_column"`, or `"tf-idf"`. +- `name_merged_clusters`: `TRUE` to name dynamic clusters across the list. Typically, you want to set this to `TRUE` when your `cluster_id` is the dynamic cluster column created by `merge_dynamic_clusters()`. +- `cluster_id`: column to name. +- `label_name`: output label column name (`"cluster_label"` by default). +- `text_columns`, `nb_terms_label`: key arguments for TF-IDF naming. + +```{r dynamic-name-clusters, eval = FALSE} +g_dynamic <- name_clusters( + graphs = g_dynamic, + method = "tf-idf", + name_merged_clusters = TRUE, + cluster_id = "dynamic_cluster_leiden", + text_columns = "source_title", + nb_terms_label = 3 +) +``` + +### `add_node_roles()` + +Nodes in a cluster can play different structural roles. `add_node_roles()` implements the Guimera-Amaral classification of node roles based on two measures: within-module degree (z-score) and participation coefficient. Use `add_node_roles()` after clustering to classify nodes according to their structural position in modules (within-module degree, participation coefficient, Guimera-Amaral roles). This helps distinguish peripheral nodes, connectors, and hubs. + + +Main parameters: + +- `module_col`: cluster/module column used to compute roles. +- `weight_col`: edge weight column. +- `z_threshold`: hub threshold for within-module z-score. + +Main outputs: + +- `within_module_degree`. +- `within_module_z`. +- `participation_coeff`. +- `role_ga`. + +```{r static-node-roles, eval = FALSE} +g_static <- add_node_roles( + graphs = g_static, + module_col = "cluster_leiden", + weight_col = "weight", + z_threshold = 2.5 +) +``` + +### `extract_tfidf()` + +Use `extract_tfidf()` to characterize cluster content from textual metadata (for instance titles, abstracts, or keywords). In a static network, cluster IDs are usually unique within the graph, so `grouping_across_list = FALSE`. +Main parameters: + +- `text_columns`: one or more text fields used to extract ngrams. +- `grouping_columns`: document units for TF-IDF (for example cluster IDs). +- `grouping_across_list`: helps disambiguate group IDs across windows. +- `n_gram`: maximum n for ngrams. +- `clean_word_method`: `"lemmatize"`, `"stemming"`, `"none"`. +- `ngrams_filter`: remove terms that are too rare globally. +- `nb_terms`: number of top terms returned per group. + +```{r static-tfidf, eval = FALSE} +tfidf_static <- extract_tfidf( + data = g_static, + text_columns = "source_title", + grouping_columns = "cluster_leiden", + grouping_across_list = FALSE, + n_gram = 2, + nb_terms = 5 +) +``` + +# Step 3: Plot networks + +Functions used: + +- `layout_networks()` +- `minimize_crossing_alluvial()` +- `color_networks()` +- `prepare_label_alluvial()` +- `prepare_label_networks()` +- `plot_alluvial()` +- `plot_networks()` +- `launch_network_app()` + +### `layout_networks()` + +Compute node coordinates before plotting. The function is a wrapper around `ggraph::ggraph()` and supports all its layout algorithms. For dynamic networks, coordinates are computed sequentially by window: the first window is computed with the selected layout, then subsequent windows are computed by reusing prior coordinates when `compute_dynamic_coordinates = TRUE`. + +Main parameters: + +- `node_id`: unique node ID column used to join coordinates. +- `layout`: layout algorithm accepted by `ggraph::create_layout()`. +- `compute_dynamic_coordinates`: reuse prior window coordinates. +- `save_coordinates`: if `TRUE`, saves coordinates in node columns `{layout}_x` and `{layout}_y` (for example `kk_x`, `kk_y`). Typically, you want to set this to `TRUE` when testing different layouts for plotting. + +The output is a `tbl_graph` (or list of `tbl_graph`) with new node columns `{layout}_x` and `{layout}_y` or `x` and `y` if `save_coordinates = FALSE`. + +Example: + +```{r static-layout} +g_static <- layout_networks( + graphs = g_static, + node_id = "source_id", + layout = "kk" +) +``` + +```{r dynamic-layout, eval = FALSE} +g_dynamic <- layout_networks( + graphs = g_dynamic, + node_id = "source_id", + layout = "fr", + compute_dynamic_coordinates = TRUE +) +``` + +### `color_networks()` + +Assign colors to nodes and edges based on a categorical attribute `column_to_color` present in the node table. Typically, it is used to color clusters from `add_clusters()`. The function supports various color input formats: a named vector of colors with a length equal to the number of unique categories in `column_to_color`, a data frame mapping categories to colors. If `color = NULL`, the function generates a color palette automatically. + +Main parameters: + +- `column_to_color`: node attribute used to define categories to color. +- `color`: : a palette or a two-column data frame mapping categories to colors. +- `unique_color_across_list`: for dynamic networks only. It controls whether the same value of `column_to_color` in different time windows should receive the same color. If set to `FALSE`, the same categorical variable will be considered as the same variable in different graphs. If set to `TRUE`, the same categorical variable will be considered as a different variable in different graphs and thus receive a different color. + +Output: + +- node column `color`. +- edge column `color` computed as a mix of source and target node colors. + +```{r static-colors} +g_static <- color_networks( + graphs = g_static, + column_to_color = "cluster_leiden", + color = NULL +) +``` + +### `prepare_label_networks()` + +Create label coordinates (`label_x`, `label_y`) for the label positioning in network plots. The function computes the average coordinates of nodes within each cluster to position the label. + +Main parameters: + +- `x`, `y`: coordinate columns used to compute label centers. +- `cluster_label_column`: column used for grouping and label text. + +```{r static-labels} +g_static <- prepare_label_networks( + graphs = g_static, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden" +) +``` + +The output is a `tbl_graph` (or list of `tbl_graph`) with new node columns `label_x` and `label_y` for label coordinates. + +### `plot_networks()` + +`plot_networks()` builds a ready-to-use network visualization from graph attributes (coordinates, colors, labels). For exploration and analysis, we strongly encourage to use launch_network_app() for interactive exploration. + +It requires node coordinates (x, y) and a cluster label column. Colors must either already exist or be generated by setting `color_networks = TRUE`. The user can also customize the plot by setting `print_plot_code = TRUE`, which prints the generated ggplot/ggraph code for manual adjustments. + +Main parameters: + +- `x`, `y`: node coordinates. +- `cluster_label_column`: displayed cluster labels. +- `node_size_column`: node size variable (`NULL` or missing column gives constant size). +- `color_column`: color column for nodes and edges. +- `color_networks`: if `TRUE`, applies `color_networks()` automatically with + `cluster_label_column` as grouping variable. +- `color`: optional palette passed to `color_networks()` when + `color_networks = TRUE`. +- `print_plot_code`: if `TRUE`, prints the generated ggplot/ggraph code for + manual customization. + +Automatic behavior: + +- if label coordinates are missing, `prepare_label_networks()` is called + automatically. +- if edge weights are missing, a constant weight of `1` is used. +- if `node_size_column` is missing, a constant node size of `1` is used. + +The output is a ggplot object. For dynamic analyses, the function returns a list of ggplot objects (one per time window) stored in the `$plot` column of each list element. + +```{r static-plot, eval = FALSE} +plot_networks( + graphs = g_static, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden", + node_size_column = NULL, + color_column = "color" +) +``` + +### `launch_network_app()` + +`launch_network_app()` extends `plot_networks()` by providing an interactive +Shiny interface for network exploration. It launches a local app with an +interactive network view. Users can click on clusters to display a table with +selected metadata and adjust visual settings (node size, edge width, labels, +edge visibility) to improve readability. For example, for a coupling network, the application allows users to explore article-level information in each cluster. + +The app expects a `tbl_graph` (or a list of `tbl_graph` for dynamic analysis), +cluster identifiers, and metadata columns to display. If the input is a list, +the app shows a dropdown menu to select the graph by list name (typically time +windows when graphs are built with `build_dynamic_networks()`). + +Main parameters: + +- `cluster_id`: node cluster column used for interaction. +- `cluster_information`: node metadata columns shown in the table (for example `c("source_author", "source_title", "source_year")`), present in node data. +- `node_id`: unique node ID. +- `node_tooltip`: optional node tooltip column for hover information. +- `node_size`: optional node size column. +- `color`: optional color column (`color_networks()` is applied if `NULL`). +- `layout`: layout algorithm available in `layout_networks()`. If `NULL`, the function assumes layout coordinates already exist in node columns `x` and `y`. + +```{r static-app, eval = FALSE} +launch_network_app( + graph_tbl = g_static, + cluster_id = "cluster_leiden", + cluster_information = c("source_author", "source_title", "source_year", "source_journal"), + node_id = "source_id", + node_tooltip = "source_label", + node_size = NULL, + color = "color", + layout = NULL +) +``` + +### `prepare_label_alluvial()` + +### `minimize_crossing_alluvial()` + +### `plot_alluvial()` + + + +# End-to-end executable example + +The chunk below runs a complete static workflow on bundled data: +network construction, clustering, layout, coloring, label preparation, and plotting. + +```{r static-end-to-end, message = FALSE, warning = FALSE} +set.seed(123) + +# 1) Input tables +nodes_ex <- subset(Nodes_stagflation, source_type == "Stagflation") + +references_ex <- Ref_stagflation + +# 2) Build network +g_pipeline <- build_network( + nodes = nodes_ex, + directed_edges = references_ex, + source_id = "source_id", + target_id = "target_id", + projection_method = "structured", + cooccurrence_method = "coupling_similarity", + edges_threshold = 1, + keep_singleton = FALSE +) + +# 3) Cluster +g_pipeline <- add_clusters( + graphs = g_pipeline, + clustering_method = "leiden", + objective_function = "modularity", + resolution = 1, + n_iterations = 1000, + seed = 123 +) + +# 4) Prepare plot attributes +g_pipeline <- layout_networks(g_pipeline, node_id = "source_id", layout = "kk") +g_pipeline <- color_networks(g_pipeline, column_to_color = "cluster_leiden") +g_pipeline <- prepare_label_networks( + g_pipeline, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden" +) + +# 5) Quick checks on generated attributes +head( + g_pipeline %>% + tidygraph::activate(nodes) %>% + as.data.frame() %>% + subset(select = c(source_id, cluster_leiden, size_cluster_leiden, x, y, color, label_x, label_y)) +) + +head( + g_pipeline %>% + tidygraph::activate(edges) %>% + as.data.frame() %>% + subset(select = c(from, to, weight, color)) +) +``` + +```{r static-end-to-end-plot, fig.width = 8, fig.height = 6, fig.alt = "Static network plot showing clustered nodes colored by community with labels positioned near cluster centers."} +plot_networks( + graphs = g_pipeline, + x = "x", + y = "y", + cluster_label_column = "cluster_leiden", + node_size_column = NULL, + color_column = "color" +) +``` + + +# Included datasets + +- `Nodes_stagflation` +- `Ref_stagflation` +- `Authors_stagflation` +- `Nodes_coupling` +- `Edges_coupling` + +# Deprecated functions + +- `community_names()` -> use `name_clusters()` +- `community_labels()` -> use `prepare_label_networks()` +- `community_colors()` -> use `color_networks()` +- `dynamic_network_cooccurrence()` -> use `build_dynamic_networks()` +- `intertemporal_cluster_naming()` -> use `merge_dynamic_clusters()` +- `leiden_workflow()` -> use `add_clusters()` +- `networks_to_alluv()` +- `tbl_main_component()` -> use `filter_components()` +- `top_nodes()` diff --git a/vignettes/workflow-network.Rmd b/vignettes/workflow-network.Rmd deleted file mode 100644 index a95e7ff..0000000 --- a/vignettes/workflow-network.Rmd +++ /dev/null @@ -1,137 +0,0 @@ ---- -title: "A Workflow for network analysis" -author: "Aurélien Goutsmedt and Alexandre Truc" -description: > - Introduction to the standards function of the networkflow package for building, manipulating - plotting, and analysing a network. -output: - rmarkdown::html_vignette: - toc: true -vignette: > - %\VignetteIndexEntry{workflow-network} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} - - -### Bibliography settings -bibliography: REFERENCES.bib -csl: chicago-author-date.csl -suppress-bibliography: false -link-citations: true ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -In the following article, we will go other the different steps to create a bibliometric network, manipulate it, prepare the plotting and eventually plot it. - -## First step: creating the network and keeping the main component - -As a point of departure, you need your bibliometric data to be prepared in a certain format:^[See how to extract and clean data from scopus [here](https://aurelien-goutsmedt.com/post/extracting-biblio-data-1/) and from Dimensions [here](https://aurelien-goutsmedt.com/post/extracting-biblio-data-2/).] - -- you need a `nodes` table. For instance, it may be a list of articles with metadata (author(s), title, journal, etc.). Nodes must have a unique identifier and all the information about a node are gathered on only one row (in case of articles, you need one row per article). -- you need a `directed_edges` table, that is a table that links your nodes with another variable that will be used to build the edges between your nodes. For instance, the table could links articles (your nodes) with the references cited by these articles. It can also be a journal or a list of authors (if you are interested in collaboration). In your `directed_edges` table, you need the identifier of the nodes (also present in the `nodes` table), and the unique identifier of the categories (references cited, journals, authors...) the nodes are linked to. - -As soon as you have a nodes and a edges file (see the [biblionetwork](https://github.com/agoutsmedt/biblionetwork) package for creating such files), you can create a graph, using tidygraph and the [tbl_graph()](https://rdrr.io/cran/tidygraph/man/tbl_graph.html) function. The next step, as it is recurrent in many network analyses, notably in bibliometric netwoks like bibliographic coupling networks would be to keep only the [main component](https://en.wikipedia.org/wiki/Component_(graph_theory)) of your network. This could be done in one step using the `tbl_main_component()` function of `networkflow`. - -```{r creating graph} -library(networkflow) - -## basic example code - -graph <- tbl_main_component(nodes = Nodes_coupling, edges = Edges_coupling, directed = FALSE, node_key = "ItemID_Ref", nb_components = 1) -print(graph) - -``` - -The parameter `nb_components` allows you to choose the number of components you want to keep. For obvious reasons, it is settled to 1 by default. - -However, it could happen in some networks (for instance co-authorship networks) that the second biggest component of your network is quite large. To avoid removing too big components without knowing it, the `tbl_main_component()` function integrates a warning that happens when a secondary component gathering more than x% of the total number of nodes is removed. The `threshold_alert` parameter is set to 0.05 by default, but you can reduce it if you really want to avoid removing relatively big components. - -```{r components} - -## basic example code - -graph <- tbl_main_component(nodes = Nodes_coupling, edges = Edges_coupling, directed = FALSE, node_key = "ItemID_Ref", threshold_alert = 0.001) -print(graph) - -``` - -## Second step: finding communities - -Once you have you tidygraph graph, an important step is to run community detection algorithms to group the nodes depending on their links. This package uses the [leidenAlg](https://cran.r-project.org/web/packages/leidenAlg/index.html) package, and its `find_partition()` function, to implement the Leiden algorithm [@traag2019]. The `leiden_workflow()` function of our package runs the Leiden algorithm and attributes a community number to each node in the `Com_ID` column, but also to each edge (depending if the `from` and `to` nodes are within the same community). - -```{r leiden, eval = FALSE} - -# creating again the graph -graph <- tbl_main_component(nodes = Nodes_coupling, edges = Edges_coupling, directed = FALSE, node_key = "ItemID_Ref", nb_components = 1) - -# finding communities -graph <- leiden_workflow(graph) -print(graph) - -``` - -You can observe that the function also gives the size of the community, by calculating the share of total nodes that are in each community. - -The function also allows to play with the `resolution` parameter of leidenAlg [`find_partition()`]() function. Varying the resolution of the algorithm results in a different partition and different number of communities. A lower resolution means less communities, and conversely. The basic resolution of the `leiden_workflow()` is set by `res_1` and equals 1 by default. You can vary this parameter, but also try a second resolution with `res_2` and a third one with `res_3`: - -```{r resolution, eval = FALSE} - -# creating again the graph -graph <- tbl_main_component(nodes = Nodes_coupling, edges = Edges_coupling, directed = FALSE, node_key = "ItemID_Ref", nb_components = 1) - -# finding communities -graph <- leiden_workflow(graph, res_1 = 0.5, res_2 = 2, res_3 = 3) -print(graph) - -``` - -Once you have detected different communities in your network, you are well on the way of the projection of your graph, but two important steps should be implemented before. First, you have to attribute some colors to each community. These colors will be used for your nodes and edges when you will project your graph with `ggraph`. The function `community_colors` of the `networkflow` package allow to do that. You just have to give it a palette (with as many colors as the number of communities for a better visualisation).^[If two connected nodes are in the same community, their edge will take the same color. If they are in different communities, their edge will have a mix of the two communities colors.] - -```{r, eval = FALSE} -# loading a palette with many colors -palette <- c("#1969B3","#01A5D8","#DA3E61","#3CB95F","#E0AF0C","#E25920","#6C7FC9","#DE9493","#CD242E","#6F4288","#B2EEF8","#7FF6FD","#FDB8D6","#8BF9A9","#FEF34A","#FEC57D","#DAEFFB","#FEE3E1","#FBB2A7","#EFD7F2","#5CAADA","#37D4F5","#F5779B","#62E186","#FBDA28","#FB8F4A","#A4B9EA","#FAC2C0","#EB6466","#AD87BC","#0B3074","#00517C","#871B2A","#1A6029","#7C4B05","#8A260E","#2E3679","#793F3F","#840F14","#401C56","#003C65","#741A09","#602A2A","#34134A","#114A1B","#27DDD1","#27DD8D","#4ADD27","#D3DD27","#DDA427","#DF2935","#DD27BC","#BA27DD","#3227DD","#2761DD","#27DDD1") - -# creating again the graph -graph <- tbl_main_component(nodes = Nodes_coupling, edges = Edges_coupling, directed = FALSE, node_key = "ItemID_Ref", nb_components = 1) - -# finding communities -graph <- leiden_workflow(graph) - -# attributing colors -graph <- community_colors(graph, palette, community_column = "Com_ID") -print(graph) -``` - -What you want to do next is to give a name automatically to your community. The `community_names()` function allows you to do that: it gives to the community the label of the node, within the community, which has the highest score in the statistics you choose. In the next exemple, we will calculate the degree of each node, and each community will take as a name the label of its highest degree node. - -```{r naming, eval = FALSE} - -library(magrittr) -library(dplyr) -library(tidygraph) - -# calculating the degree of nodes - graph <- graph %>% - activate(nodes) %>% - mutate(degree = centrality_degree()) - -# giving names to communities - graph <- community_names(graph, ordering_column = "degree", naming = "Author_date", community_column = "Com_ID") - print(graph) - -``` - - -## Third step: plotting the network - -### Preparing the plot - - - -## References From 315b8f93ae56acd278870b8e081c1ea7ec8ddfd0 Mon Sep 17 00:00:00 2001 From: tdelcey_w Date: Thu, 12 Feb 2026 10:54:43 +0100 Subject: [PATCH 2/2] add todolist.md --- TODOLIST_DEV.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 TODOLIST_DEV.md diff --git a/TODOLIST_DEV.md b/TODOLIST_DEV.md new file mode 100644 index 0000000..04bcd5a --- /dev/null +++ b/TODOLIST_DEV.md @@ -0,0 +1,17 @@ +# Todolist - Push vers dev + +Voila l'eval de GPT qui a acces au package complet. + +Le package est globalement bien structure (API claire, workflow coherent, docs presentes), mais il reste plusieurs points qualite importants avant une version vraiment robuste. + +## Points principaux releves + +- Pas de suite de tests (`tests/` absent): risque de regression eleve. +- CI incoherente: le README affiche un badge `R-CMD-check`, mais le workflow correspondant n'est pas present dans `.github/workflows/` (seulement `pkgdown`). +- Incoherences de deprecation: + - `filter_components()` est documentee comme "deprecated" mais avec badge `experimental`. + - `tbl_main_component()` annonce un remplacement par `extract_main_component()` qui n'existe pas. +- `NEWS.md` mentionne `layout_clusters()` alors que la fonction n'existe pas dans `R/`. +- Dette technique legere: + - duplication de `mixcolor()` dans deux fichiers, + - `rename_at()` encore utilise (fonction `dplyr` superseded).