Skip to contents

Introduction

The influencer package provides tools for calculating influence scores of neurons in connectomes using linear dynamical models. This vignette demonstrates the basic usage with simple synthetic data that doesn’t require external authentication.

Setup

library(influencer)
library(dplyr)
library(ggplot2)

# Set random seed for reproducibility
set.seed(42)

Basic Usage with Synthetic Data

Let’s create a simple network to demonstrate the core functionality:

# Create a simple 6-neuron network
edges <- data.frame(
  pre = c("A", "B", "C", "D", "A", "B"),
  post = c("B", "C", "D", "E", "C", "D"), 
  count = c(10, 8, 12, 6, 5, 15),
  norm = c(0.5, 0.4, 0.6, 0.3, 0.25, 0.75)
)

meta <- data.frame(
  root_id   = c("A", "B", "C", "D", "E"),
  cell_type = c("input", "interneuron", "interneuron", "output", "output"),
  # `top_nt` is required by `signed = TRUE` (and by `excluded_nts`); we set
  # it here so the signed-mode example below can run.
  top_nt    = c("acetylcholine", "gaba", "acetylcholine", "glutamate", "acetylcholine")
)

print("Edge list:")
#> [1] "Edge list:"
print(edges)
#>   pre post count norm
#> 1   A    B    10 0.50
#> 2   B    C     8 0.40
#> 3   C    D    12 0.60
#> 4   D    E     6 0.30
#> 5   A    C     5 0.25
#> 6   B    D    15 0.75
print("Metadata:")
#> [1] "Metadata:"
print(meta)
#>   root_id   cell_type        top_nt
#> 1       A       input acetylcholine
#> 2       B interneuron          gaba
#> 3       C interneuron acetylcholine
#> 4       D      output     glutamate
#> 5       E      output acetylcholine

Creating an Influence Calculator

# Create influence calculator using the R implementation
ic <- influence_calculator_r(edgelist_simple = edges, meta = meta)

# Print some information about the calculator
cat("Network has", nrow(ic$meta), "neurons and", nrow(ic$edgelist_simple), "connections\n")
#> Network has 5 neurons and connections

Calculating Influence Scores

# Calculate influence of neuron "A" on the network
influence_scores_A <- ic$calculate_influence("A")
print("Influence of neuron A:")
#> [1] "Influence of neuron A:"
print(influence_scores_A)
#>   matrix_index id is_seed Influence_score_(unsigned) adjusted_influence
#> 1            0  A    TRUE               1.000000e+00           24.00000
#> 2            1  B   FALSE               2.969840e+03           31.99626
#> 3            2  C   FALSE               7.057443e+06           39.76959
#> 4            3  D   FALSE               2.516460e+10           47.94870
#> 5            4  E   FALSE               4.484089e+13           55.43414

# Calculate influence of neuron "B"  
influence_scores_B <- ic$calculate_influence("B")
print("Influence of neuron B:")
#> [1] "Influence of neuron B:"
print(influence_scores_B)
#>   matrix_index id is_seed Influence_score_(unsigned) adjusted_influence
#> 1            0  A   FALSE               0.000000e+00            0.00000
#> 2            1  B    TRUE               1.000000e+00           24.00000
#> 3            2  C   FALSE               2.375872e+03           31.77312
#> 4            3  D   FALSE               8.471604e+06           39.95223
#> 5            4  E   FALSE               1.509558e+10           47.43767

Visualizing Results

# Combine results for comparison
influence_scores_A$seed <- "A"
influence_scores_B$seed <- "B"
combined_results <- rbind(influence_scores_A, influence_scores_B)

# Create comparison plot
ggplot(combined_results, aes(x = id, y = adjusted_influence, fill = seed)) +
  geom_col(position = "dodge") +
  labs(
    title = "Influence Scores Comparison",
    subtitle = "Comparing influence propagation from neurons A and B",
    x = "Target Neuron",
    y = "Adjusted Influence Score",
    fill = "Seed Neuron"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Bar chart comparing influence scores from neurons A and B across target neurons C, D, and E. Shows that neuron A has higher influence on targets C and D, while neuron B has higher influence on target E.

Multiple Seed Neurons

You can also calculate influence from multiple seed neurons simultaneously:

# Calculate influence from both A and B together
combined_influence <- ic$calculate_influence(c("A", "B"))
print("Combined influence from A and B:")
#> [1] "Combined influence from A and B:"
print(combined_influence)
#>   matrix_index id is_seed Influence_score_(unsigned) adjusted_influence
#> 1            0  A    TRUE               1.000000e+00           24.00000
#> 2            1  B    TRUE               2.970840e+03           31.99660
#> 3            2  C   FALSE               7.059819e+06           39.76993
#> 4            3  D   FALSE               2.517307e+10           47.94904
#> 5            4  E   FALSE               4.485599e+13           55.43448

# Compare individual vs combined influence
comparison <- merge(
  influence_scores_A[, c("id", "adjusted_influence")],
  combined_influence[, c("id", "adjusted_influence")],
  by = "id",
  suffixes = c("_A_only", "_A_and_B")
)
print(comparison)
#>   id adjusted_influence_A_only adjusted_influence_A_and_B
#> 1  A                  24.00000                   24.00000
#> 2  B                  31.99626                   31.99660
#> 3  C                  39.76959                   39.76993
#> 4  D                  47.94870                   47.94904
#> 5  E                  55.43414                   55.43448

Understanding the Results

The influence scores represent how much each neuron is affected by the seed neurons through the network dynamics. Key points:

  • Raw influence scores: Direct output from the linear dynamical model
  • Adjusted influence: max(0, log(influence_score) + 24) - provides a meaningful scale
  • Additive effects: Influence from multiple seeds combines linearly

Signed vs Unsigned Networks

The package supports both signed and unsigned connectivity:

# Create calculator with signed connectivity. The library has no per-organism
# default for which transmitters are inhibitory; you must supply
# `inhibitory_nts` explicitly when `signed = TRUE`. (`excluded_nts` is also
# accepted, for transmitter classes that gate both excitatory and inhibitory
# receptors and so cannot be assigned a single sign safely.)
ic_signed <- influence_calculator_r(
  edgelist_simple = edges,
  meta = meta,
  signed = TRUE,
  inhibitory_nts = c("glutamate", "gaba", "serotonin", "octopamine")
)

# Results will be similar for this example since we don't have inhibitory neurons marked
influence_signed <- ic_signed$calculate_influence("A")
print("Signed network influence (same as unsigned for this example):")
#> [1] "Signed network influence (same as unsigned for this example):"
print(head(influence_signed))
#>   matrix_index id is_seed Influence_score_(signed) adjusted_influence
#> 1            0  A    TRUE             1.000000e+00           24.00000
#> 2            1  B   FALSE             2.812350e+03           31.94178
#> 3            2  C   FALSE            -6.326042e+06          -39.66019
#> 4            3  D   FALSE            -2.136112e+10          -47.78484
#> 5            4  E   FALSE             3.604496e+13           55.21579

Performance Notes

The R implementation includes smart caching - the first calculation does matrix decomposition, but subsequent calculations with the same network are much faster:

# Time the first calculation
system.time({
  result1 <- ic$calculate_influence("A")
})
#>    user  system elapsed 
#>   0.001   0.000   0.001

# Time a subsequent calculation (should be faster due to caching)
system.time({
  result2 <- ic$calculate_influence("C")
})
#>    user  system elapsed 
#>   0.001   0.000   0.000

Next Steps

For real-world applications:

  1. Large networks: The package handles large connectomes efficiently
  2. Data formats: Supports both data frames and SQLite databases
  3. Python integration: Optional Python backend for specialized use cases
  4. Real data: See the BANC connectome analysis vignette for biological examples

Session Information

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
#>  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
#>  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
#> [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
#> 
#> time zone: UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] ggplot2_4.0.3    dplyr_1.2.1      influencer_2.0.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] sass_0.4.10        generics_0.1.4     RSQLite_3.53.3     lattice_0.22-9    
#>  [5] digest_0.6.39      magrittr_2.0.5     evaluate_1.0.5     grid_4.6.1        
#>  [9] RColorBrewer_1.1-3 fastmap_1.2.0      blob_1.3.0         jsonlite_2.0.0    
#> [13] Matrix_1.7-5       RSpectra_0.16-2    DBI_1.3.0          scales_1.4.0      
#> [17] textshaping_1.0.5  jquerylib_0.1.4    cli_3.6.6          rlang_1.3.0       
#> [21] bit64_4.8.2        withr_3.0.3        cachem_1.1.0       yaml_2.3.12       
#> [25] otel_0.2.0         tools_4.6.1        memoise_2.0.1      reticulate_1.46.0 
#> [29] vctrs_0.7.3        R6_2.6.1           png_0.1-9          lifecycle_1.0.5   
#> [33] fs_2.1.0           htmlwidgets_1.6.4  bit_4.6.0          ragg_1.5.2        
#> [37] pkgconfig_2.0.3    desc_1.4.3         pkgdown_2.2.1      pillar_1.11.1     
#> [41] bslib_0.11.0       gtable_0.3.6       glue_1.8.1         Rcpp_1.1.2        
#> [45] systemfonts_1.3.2  xfun_0.60          tibble_3.3.1       tidyselect_1.2.1  
#> [49] knitr_1.51         farver_2.1.2       htmltools_0.5.9    labeling_0.4.3    
#> [53] rmarkdown_2.31     compiler_4.6.1     S7_0.2.2