# **MODIFY THIS CHUNK**
library(here)
kundaje_dir    <- trimws(readr::read_lines(here("code/AK_PROJ_DIR.txt")))
doc_id         <- "04c"
out            <- here( "output/03-chrombpnet/03-syntax/", doc_id); dir.create(out, recursive = TRUE)
figout         <- here( "figures/03-chrombpnet/03-syntax", doc_id, "/"); dir.create(figout, recursive = TRUE)
chrombpnet_dir <- here( "output/03-chrombpnet")

1 Overview

Here, we load the results of in silico marginalizations to assess motif cooperativity/synergy and syntax constraints.

Firstly, for each composite motif, we focus on the cluster with the most instances, and evaluate synergy in that cell type. We will assign motif pairs as having synergy or not, and having hard or soft syntax (or both or neither).

Secondly, we run the in silico marginalizations for every composite motif in every cell type, to more generally assess specificity of the results and investigate model predictions on motifs for TFs that are not expressed to be co-expressed.

2 Set up

library(dplyr)
library(tidyr)
library(ggplot2)
library(readr)
library(scales)
library(glue)
library(purrr)
library(stringr)
library(ggrepel)
library(cowplot)
library(pheatmap)
library(ggseqlogo)
library(universalmotif)
library(TFBSTools)

# for interactive stuff
library(plotly)
library(reactable)
library(shiny)

script_path <- here( "code/utils/")
source(file.path(script_path, "plotting_config.R"))
source(file.path(script_path, "hdma_palettes.R"))
source(file.path(script_path, "sj_scRNAseq_helpers.R"))
source(file.path(script_path, "chrombpnet_utils.R"))

ggplot2::theme_set(theme_BOR() + theme(strip.background = element_blank()))

3 Load data

3.1 Motif data

# load hits
hits_all <- readRDS(file.path(chrombpnet_dir, "03-syntax/01/hits.Rds")) %>% bind_rows()

# load intermediate objects
load(file.path(chrombpnet_dir, "03-syntax/01/intermediate_obj.Rda"))

Load merged modisco reports:

cwm_means <- read_tsv(here("output/03-chrombpnet/02-compendium/modisco_compiled/cwm_sums_df.tsv"))
## Rows: 6362 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): cluster, pattern_class, motif, component_pattern
## dbl (4): cwm_sum, abs_cwm_sum, cwm_mean, abs_cwm_mean
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
modisco_merged <- read_tsv(here("output/03-chrombpnet/02-compendium/modisco_compiled_anno/modisco_merged_reports.tsv")) %>% 
  # get short cluster ID
  left_join(cluster_meta %>% dplyr::select(Cluster, Cluster_ChromBPNet),
            by = c("component_celltype" = "Cluster_ChromBPNet")) %>% 
  left_join(cwm_means, by = "component_pattern")
## Rows: 6362 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (5): merged_pattern, component_celltype, pattern_class, pattern, compone...
## dbl (1): n_seqlets
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(modisco_merged)
## # A tibble: 6 × 14
##   merged_pattern            component_celltype pattern_class.x pattern n_seqlets
##   <chr>                     <chr>              <chr>           <chr>       <dbl>
## 1 neg.Average_12__merged_p… Spleen_c5          neg_patterns    patter…        88
## 2 neg.Average_12__merged_p… Spleen_c0          neg_patterns    patter…       461
## 3 neg.Average_12__merged_p… Skin_c5            neg_patterns    patter…       302
## 4 neg.Average_12__merged_p… Heart_c13          neg_patterns    patter…       128
## 5 neg.Average_12__merged_p… Skin_c7            neg_patterns    patter…       708
## 6 neg.Average_12__merged_p… Heart_c5           neg_patterns    patter…        47
## # ℹ 9 more variables: component_pattern <chr>, Cluster <chr>, cluster <chr>,
## #   pattern_class.y <chr>, motif <chr>, cwm_sum <dbl>, abs_cwm_sum <dbl>,
## #   cwm_mean <dbl>, abs_cwm_mean <dbl>

3.2 In silico marginalization results

3.2.1 Experiments in the cell type clusters of focus

Path to the full pipeline for clusters of focus:

ism_dir <- file.path(chrombpnet_dir, "03-syntax/04b/in_silico_marginalization_full/")
fs::dir_exists(ism_dir)
## /oak/stanford/groups/wjg/skim/projects/HDMA-public/output/03-chrombpnet/03-syntax/04b/in_silico_marginalization_full/ 
##                                                                                                                  TRUE

List of composites to test:

compo_to_test <- read_tsv(here("code/03-chrombpnet/03-syntax/04b-composites_to_test.tsv")) %>% 
  filter(test_spacing == "Y")
## Rows: 157 Columns: 26
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (15): motif_name, Cluster, category, annotation_broad, component_motifA,...
## dbl  (8): n_hits_per_cluster, idx_uniq, variant_idx, total_hits, start_A, en...
## lgl  (3): composite_cwm_fwd, componentA_cwm_fwd, componentB_cwm_fwd
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
compo_to_test$motif_name_safe <- gsub("\\/", "\\.", compo_to_test$motif_name)
compo_to_test$done <- ifelse(file.exists(file.path(ism_dir, compo_to_test$motif_name_safe, compo_to_test$Cluster, ".done")),
                             TRUE,
                             FALSE)

glue("{sum(compo_to_test$done)/nrow(compo_to_test)*100}%")
## 100%
compo_to_test <- compo_to_test %>%
  dplyr::rename(seqA = test_seqA, seqB = test_seqB)

Check for duplicates:

# sort the two motif sequences alphabetically so we can find duplicates even
# when the order is swapped
pairs <- map_dfr(1:nrow(compo_to_test), function(i) {
  
  motifs <- compo_to_test[i, c("seqA", "seqB")] %>% unlist() %>% sort()
  data.frame(motif_name = compo_to_test$motif_name[i],
             A = motifs[[1]],
             B = motifs[[2]])
  
})

# should be empty if no duplicates.
pairs %>% group_by(A, B) %>% mutate(n = n()) %>% filter(n > 1)
## # A tibble: 0 × 4
## # Groups:   A, B [0]
## # ℹ 4 variables: motif_name <chr>, A <chr>, B <chr>, n <int>

Outputs of the in silico marginalization experiments:

result_outs <- pmap_dfr(list(compo_to_test$motif_name_safe, compo_to_test$Cluster, compo_to_test$motif_name),
                        ~ data.table::fread(file.path(ism_dir, ..1, ..2, "results.tsv"), data.table = FALSE) %>% 
                          mutate(motif_name = ..3)) %>% 
  left_join(compo_to_test %>% dplyr::select(motif_name, category), by = "motif_name") %>% 
  dplyr::select(-seqA_palindrome, -seqB_palindrome)

Z-scores on the marginal joint effects:

z_scores <- pmap_dfr(list(compo_to_test$motif_name_safe, compo_to_test$Cluster, compo_to_test$motif_name),
                     function(motif_safe, cluster, motif) {
                       
                       df <- data.table::fread(file.path(ism_dir, motif_safe, cluster, "Z_scores.tsv"), data.table = FALSE) %>% 
                         mutate(motif_name = motif)
                       df
                       
                     })  %>% 
  left_join(compo_to_test %>% dplyr::select(motif_name, category), by = "motif_name")

Summarized effects for solo motifs:

solo_df <- pmap_dfr(list(compo_to_test$motif_name_safe, compo_to_test$Cluster, compo_to_test$motif_name),
                    ~ data.table::fread(file.path(ism_dir, ..1, ..2, "summarized_effects_solo.tsv"),
                                        data.table = FALSE) %>% 
                      mutate(motif_name = ..3))  %>% 
  left_join(compo_to_test %>% dplyr::select(motif_name, category), by = "motif_name") %>% 
  dplyr::rename(orientation = key)

Summarized effects for spaced motifs:

spacing_df <- pmap_dfr(list(compo_to_test$motif_name_safe, compo_to_test$Cluster, compo_to_test$motif_name),
                       ~ data.table::fread(file.path(ism_dir, ..1, ..2, "summarized_effects_per_spacing.tsv"), data.table = FALSE) %>% 
                         mutate(motif_name = ..3)) %>% 
  left_join(compo_to_test %>% dplyr::select(motif_name, category, seqA, seqB), by = "motif_name") %>% 
  dplyr::rename(orientation = key) %>% 
  rowwise() %>% 
  mutate(dist_center_to_center = round(nchar(seqA)/2) + spacing + round(nchar(seqB)/2))

3.2.2 All experiments

All experiments in all cell types:

ism_dir_all <- file.path(chrombpnet_dir, "03-syntax/04b/in_silico_marginalization")
fs::dir_exists(ism_dir_all)
## /oak/stanford/groups/wjg/skim/projects/HDMA-public/output/03-chrombpnet/03-syntax/04b/in_silico_marginalization 
##                                                                                                            TRUE

List of composites to test:

# get all tests performed (all motif pairs x all clusters)
all_tests <- expand_grid(
  motif_name_safe = compo_to_test$motif_name_safe,
  cluster = chrombpnet_models_keep$Cluster
)

all_tests$done <- ifelse(fs::file_exists(file.path(ism_dir_all, all_tests$motif_name_safe, all_tests$cluster, ".done")),
                         TRUE,
                         FALSE)

sum(all_tests$done)
## [1] 26082
sum(all_tests$done)/nrow(all_tests)
## [1] 1
nrow(all_tests)-sum(all_tests$done)
## [1] 0
all_tests2 <- all_tests %>% filter(done) %>%
  left_join(compo_to_test %>% dplyr::select(-Cluster, -done), by = "motif_name_safe")

Outputs of the in silico marginalization experiments:

result_outs_allexp <- map2_dfr(all_tests2$motif_name_safe, all_tests2$cluster,
                            ~ data.table::fread(file.path(ism_dir_all, .x, .y, "results.tsv"), data.table = FALSE)
                            %>% mutate(cluster = .y)) %>% 
  left_join(compo_to_test %>% dplyr::select(motif_name, category), by = "motif_name") %>% 
  dplyr::select(-seqA_palindrome, -seqB_palindrome)

nrow(result_outs_allexp)
## [1] 26082

Outputs of the solo tests:

solo_df_allexp <- pmap_dfr(list(all_tests2$motif_name_safe, all_tests2$cluster, all_tests2$motif_name),
                    ~ data.table::fread(file.path(ism_dir_all, ..1, ..2, "summarized_effects_solo.tsv"),
                                        data.table = FALSE) %>% 
                      mutate(motif_name = ..3, cluster = ..2))

head(solo_df_allexp)
##     key counts_after_mean counts_after_sd  effect_mean   effect_sd  motif_name
## 1     A          2.405999       0.1453060  0.021411831 0.010908893 1|AP-2_BHLH
## 2     B          2.379369       0.1503053 -0.005217277 0.010656357 1|AP-2_BHLH
## 3 A + B          4.785368       0.2955811  0.016194545 0.020554082 1|AP-2_BHLH
## 4     A          2.436762       0.1218845 -0.001816668 0.001396795 1|AP-2_BHLH
## 5     B          2.429812       0.1221980 -0.008766225 0.003088963 1|AP-2_BHLH
## 6 A + B          4.866573       0.2440730 -0.010582877 0.004265720 1|AP-2_BHLH
##      cluster
## 1 Adrenal_c0
## 2 Adrenal_c0
## 3 Adrenal_c0
## 4 Adrenal_c1
## 5 Adrenal_c1
## 6 Adrenal_c1

Save intermediates:

save(spacing_df, solo_df, z_scores, result_outs, compo_to_test, result_outs_allexp, solo_df_allexp,
     file = glue("{out}/intermediate_obj.Rda"))

4 Palettes

blues <- RColorBrewer::brewer.pal(6, "Blues")
purples <- RColorBrewer::brewer.pal(6, "Purples")

palette_orientation_hetero <- c('A,B HT' = blues[3],
                                'B,A HT' = blues[4],
                                'HH'     = blues[5],
                                'TT'     = blues[6])

palette_orientation_homo <- c('HT' = purples[2],
                              'HH' = purples[4],
                              'TT' = purples[6])

palette_coop <- c("homo - not cooperative"   = "gray70",
                  "hetero - not cooperative" = "gray70",
                  "homo - cooperative"       = "#7696f5",
                  "hetero - cooperative"     = "#ab7ec2",
                  "homo - specific"          = "royalblue3",
                  "hetero - specific"        = "darkorchid4")

shapemap_result <- c("no synergy"  = 1,
                     "soft"        = 24,
                     "hard & soft" = 23,
                     "hard"        = 22)

cmap_category["not cooperative"] <- "gray80"

palette_motifs <- colorRampPalette(RColorBrewer::brewer.pal(9, "Blues")[3:9])(n=nrow(compo_to_test))

5 Data wrangling

We want to combine results into one dataframe:

# join results
all_results_best <- compo_to_test %>%
  dplyr::select(motif_name, Cluster, n_hits_per_cluster, idx_uniq, annotation_broad, component_motifA, component_motifB, seqA, seqB) %>% 
  left_join(result_outs, by = "motif_name") %>% 
  left_join(z_scores %>% dplyr::select(-category),
            by = c("motif_name", "best_orientation" = "orientation", "best_spacing" = "spacing")) %>% 
  left_join(spacing_df %>%
              dplyr::select(-category, -effect_mean, -effect_sd, -seqA, -seqB) %>% 
              dplyr::rename(best_counts_after_mean = counts_after_mean,
                            best_counts_after_sd = counts_after_sd),
            by = c("motif_name", "best_orientation" = "orientation", "best_spacing" = "spacing")) %>% 
  left_join(solo_df %>% 
              dplyr::filter(orientation == "A + B") %>% 
              dplyr::select(motif_name,
                            sum_counts_after_mean = counts_after_mean,
                            sum_counts_after_sd = counts_after_sd,
                            sum_effect = effect_mean)) %>% 
  # the maximum difference between joint vs independent effects across all arrangements
  mutate(joint_vs_ind_max = joint_effect - sum_effect)
## Joining with `by = join_by(motif_name)`
# adjust p-value
all_results_best$joint_vs_sum_p_value_adj <- p.adjust(all_results_best$joint_vs_sum_p_value, method = "BH")

We want to calculate the difference in joint/independent effects for each arrangement;

all_results_spacing <- spacing_df %>% 
  dplyr::rename(joint_effect = effect_mean) %>% 
  left_join(solo_df %>% filter(orientation == "A + B") %>%
              dplyr::select(-orientation, -counts_after_mean, -counts_after_sd, -effect_sd, sum_effect = effect_mean),
            by = c("motif_name", "category")) %>% 
  mutate(joint_vs_ind_per_arrangement = joint_effect - sum_effect)

Similarly, for the set of tests of all motifs in all cell types, we compute difference between joint and independent effects:

# adjust p-value
result_outs_allexp$joint_vs_sum_p_value_adj <- p.adjust(result_outs_allexp$joint_vs_sum_p_value, method = "BH")

all_results_allexp <- result_outs_allexp %>% 
  left_join(solo_df_allexp %>% filter(key == "A + B") %>%
              mutate(sum_effect = effect_mean) %>% 
              dplyr::select(-key, -counts_after_mean, -counts_after_sd, -effect_sd, -effect_mean),
            by = c("motif_name", "cluster")) %>%
  mutate(joint_vs_ind_max = joint_effect - sum_effect) %>% 
  mutate(log10padj = -log10(joint_vs_sum_p_value_adj))

Let’s annotate the best orientation for each motif:

all_results_spacing$is_best_orientation <- FALSE

get_best_orientation <- function(motif) {
  
  all_results_best %>% filter(motif_name == motif) %>% pull(best_orientation)
  
}

motifs <- unique(all_results_spacing$motif_name)
print(motifs)
##   [1] "1|AP-2_BHLH"                            
##   [2] "10|BHLH:ATOH/NEUROD_HD:DLX/LHX#1"       
##   [3] "104|BZIP:ATF/CREB_ETS"                  
##   [4] "105|BZIP:ATF/CREB_ETS:ELF/ETV"          
##   [5] "106|BZIP:ATF/CREB_MEF2"                 
##   [6] "110|BZIP:ATF/CREB_SP/KLF#2"             
##   [7] "112|BZIP:ATF/CREB_TEAD#2"               
##   [8] "12|BHLH:ATOH/NEUROD_MEF2"               
##   [9] "121|BZIP:CEBP_FOX#2"                    
##  [10] "123|BZIP:CEBP_NFI"                      
##  [11] "124|BZIP:CEBP_NR2/RXR"                  
##  [12] "125|BZIP:CEBP_TEAD"                     
##  [13] "128|BZIP:DBP/HLF_FOX"                   
##  [14] "130|BZIP:DBP/HLF_NKX"                   
##  [15] "139|BZIP:FOSL/JUND_ETS"                 
##  [16] "14|BHLH:MXI1_BHLH:TWIST/ZBTB"           
##  [17] "140|BZIP:FOSL/JUND_FOX"                 
##  [18] "141|BZIP:FOSL/JUND_IKZF1"               
##  [19] "142|BZIP:FOSL/JUND_NR:ESRRA/NR5A#1"     
##  [20] "144|BZIP:FOSL/JUND_TEAD"                
##  [21] "146|BZIP:MAFG/MAFF_BZIP:MAFG/MAFF"      
##  [22] "147|BZIP:MAFG/MAFF_TEAD"                
##  [23] "15|BHLH:NHLH/TFAP_NFY"                  
##  [24] "152|CTCF_TBP"                           
##  [25] "156|EBF_ETS:ELF/ETV"                    
##  [26] "16|BHLH:OLIG/NEUROG_MEF2"               
##  [27] "162|ETS:ELF/ETV_ETS:ELF/ETV#1"          
##  [28] "163|ETS:ELF/ETV_FOX"                    
##  [29] "164|ETS:ELF/ETV_NFY"                    
##  [30] "165|ETS:ELF/ETV_SP/KLF#1"               
##  [31] "17|BHLH:OLIG/NEUROG_SOX"                
##  [32] "177|ETS:ELF/SPIB_ETS:ELF/SPIB#2"        
##  [33] "185|ETS:ELF/SPIB_FOX"                   
##  [34] "187|ETS:ELF/SPIB_GATA#2"                
##  [35] "191|ETS:ELF/SPIB_NFI#4"                 
##  [36] "193|ETS:ELF/SPIB_NFY"                   
##  [37] "199|ETS:ELF/SPIB_NR:ESRRA/NR5A#5"       
##  [38] "201|ETS:ELF/SPIB_RUNX#1"                
##  [39] "208|ETS:ELF/SPIB_SOX#6"                 
##  [40] "209|ETS:ELF/SPIB_SP/KLF"                
##  [41] "215|ETS_ETS#1"                          
##  [42] "217|ETS_FOX#1"                          
##  [43] "219|ETS_IKZF1"                          
##  [44] "221|ETS_NFAT#2"                         
##  [45] "224|ETS_NR:ESRRA/NR5A#2"                
##  [46] "225|ETS_SOX"                            
##  [47] "226|ETS_SP/KLF#1"                       
##  [48] "240|FOX_FOX#3"                          
##  [49] "242|FOX_GATA#2"                         
##  [50] "245|FOX_NFI"                            
##  [51] "25|BHLH:TFAP/MYOD_BHLH:TFAP/MYOD#2"     
##  [52] "253|FOX_NKX#7"                          
##  [53] "255|FOX_NR:HNF4A/HNF4G"                 
##  [54] "256|FOX_NR:NR2F/RXRG"                   
##  [55] "257|FOX_RFX"                            
##  [56] "258|FOX_SOX"                            
##  [57] "263|GATA1_TAL1"                         
##  [58] "266|GATA_GATA#3"                        
##  [59] "271|GATA_HD:MEIS/TGIF/TBX#1"            
##  [60] "273|GATA_MEF2#1"                        
##  [61] "278|GATA_NFI"                           
##  [62] "280|GATA_NR:ESRRA/NR5A#2"               
##  [63] "281|GATA_NR:NR4A/NR2C"                  
##  [64] "283|GATA_SP/KLF#2"                      
##  [65] "285|GATA_TEAD"                          
##  [66] "288|GRHL_GRHL#1"                        
##  [67] "290|GRHL_TEAD#1"                        
##  [68] "30|BHLH:TFAP/MYOD_BHLH:TWIST/ZBTB"      
##  [69] "301|HD:DLX/LHX_HD:MEIS/TGIF/TBX"        
##  [70] "303|HD:DLX/LHX_POU"                     
##  [71] "307|HD:MEIS/TGIF/TBX_HD:MEIS/TGIF/TBX#1"
##  [72] "309|HD:MEIS/TGIF/TBX_HD:PAX/VSX"        
##  [73] "310|HD:MEIS/TGIF/TBX_HD:PITX/OTX"       
##  [74] "311|HD:MEIS/TGIF/TBX_MEF2"              
##  [75] "32|BHLH:TFAP/MYOD_BZIP:FOSL/JUND#2"     
##  [76] "321|HD:PITX/OTX_HD:PITX/OTX#4"          
##  [77] "322|HD:PITX/OTX_HD:SIX/ZNF"             
##  [78] "323|HD:PITX/OTX_SP/KLF"                 
##  [79] "326|HD_HD#1"                            
##  [80] "33|BHLH:TFAP/MYOD_ETS"                  
##  [81] "330|HD_NFI#1"                           
##  [82] "338|IKZF1_NR"                           
##  [83] "339|IKZF1_RUNX"                         
##  [84] "34|BHLH:TFAP/MYOD_ETS:ELF/SPIB"         
##  [85] "340|IRF/STAT_IRF/STAT#1"                
##  [86] "345|MEF2_NFI"                           
##  [87] "349|MEF2_TBP"                           
##  [88] "35|BHLH:TFAP/MYOD_FOX#1"                
##  [89] "351|NFAT_NFAT#1"                        
##  [90] "354|NFAT_SOX#1"                         
##  [91] "357|NFI_NR2E1"                          
##  [92] "368|NFY_NFY#1"                          
##  [93] "371|NFY_SP/KLF#2"                       
##  [94] "38|BHLH:TFAP/MYOD_GATA"                 
##  [95] "382|NKX_NKX#5"                          
##  [96] "389|NKX_TEAD#2"                         
##  [97] "39|BHLH:TFAP/MYOD_HD:PBX/PKNOX"         
##  [98] "393|NR:ESRRA/NR5A_SOX"                  
##  [99] "395|NR:HNF4A/HNF4G_NR:HNF4A/HNF4G"      
## [100] "40|BHLH:TFAP/MYOD_ROR"                  
## [101] "402|NR_NR#2"                            
## [102] "409|PAX_SOX"                            
## [103] "41|BHLH:TFAP/MYOD_SP/KLF"               
## [104] "413|POU4_POU4"                          
## [105] "414|POU_POU#1"                          
## [106] "416|POU_RUNX"                           
## [107] "422|RFX_RUNX"                           
## [108] "423|RFX_SOX"                            
## [109] "424|RFX_SP/KLF"                         
## [110] "428|RUNX_RUNX#1"                        
## [111] "430|RUNX_TCF7L/LEF"                     
## [112] "434|SOX_SOX#1"                          
## [113] "439|SP/KLF_SP/KLF#3"                    
## [114] "446|SRF_TEAD"                           
## [115] "452|TEAD_TEAD"                          
## [116] "46|BHLH:TWIST/ZBTB_BHLH:TWIST/ZBTB"     
## [117] "467|p53_p53#1"                          
## [118] "47|BHLH:TWIST/ZBTB_HD"                  
## [119] "48|BHLH:TWIST/ZBTB_HD:PAX/VSX"          
## [120] "5|BHLH:ASCL/TCF_ETS:ELF/SPIB"           
## [121] "55|BHLH:USF/BHLHE_ETS:ELF/SPIB"         
## [122] "56|BHLH:USF/BHLHE_NFY"                  
## [123] "59|BHLH_BHLH:ATOH/NEUROD"               
## [124] "6|BHLH:ASCL/TCF_TCF7L/LEF"              
## [125] "60|BHLH_BHLH:MXI1"                      
## [126] "63|BHLH_BHLH:TWIST/ZBTB#2"              
## [127] "65|BHLH_BZIP:ATF/CREB#1"                
## [128] "69|BHLH_EBF"                            
## [129] "71|BHLH_HD#2"                           
## [130] "72|BHLH_HD:MEIS/TGIF/TBX#1"             
## [131] "74|BHLH_HD:PBX1/PDX1"                   
## [132] "75|BHLH_HD:PITX/OTX#1"                  
## [133] "79|BHLH_IKZF1"                          
## [134] "80|BHLH_MEF2#1"                         
## [135] "84|BHLH_NFI"                            
## [136] "9|BHLH:ATOH/NEUROD_BHLH:ATOH/NEUROD"    
## [137] "91|BHLH_RUNX#3"                         
## [138] "97|BHLH_p53"
for (i in seq_along(motifs)) {
  
  best_ori <- get_best_orientation(motifs[i])
  all_results_spacing[all_results_spacing$motif_name == motifs[i] & all_results_spacing$orientation == best_ori, ]$is_best_orientation <- TRUE
  
}

Let’s compute the max difference in joint vs ind. effects at the best orientation, in the 20-150bp range:

tmp <- all_results_spacing %>% 
  filter(is_best_orientation) %>% 
  filter(spacing %in% 20:150) %>%
  group_by(motif_name) %>%
  slice_max(n = 1, order_by = joint_effect) %>%
  mutate(joint_vs_ind_med_distance = joint_effect - sum_effect) %>% 
  dplyr::select(motif_name, joint_vs_ind_med_distance) %>% 
  ungroup()


all_results_best <- all_results_best %>% left_join(tmp, by = "motif_name")

6 Assess coooperativity and syntax requirements

6.1 Distribution of predicted counts

What’s the distribution of counts?

# first, get the mean
motif_order_mean <- spacing_df %>% 
  group_by(motif_name) %>% 
  summarize(mean_counts = mean(counts_after_mean)) %>% 
  arrange(desc(mean_counts)) %>% 
  pull(motif_name)

spacing_df %>% 
  mutate(motif_name = factor(motif_name, levels = motif_order_mean)) %>% 
  mutate(upper = counts_after_mean + counts_after_sd,
         lower = counts_after_mean - counts_after_sd) %>% 
  ggplot(aes(x = motif_name, y = counts_after_mean)) +
  geom_point(aes(fill = category), shape = 21, color = "white", size = 2, alpha = 0.5) +
  # geom_errorbar(aes(color = category, ymin = lower, ymax = upper), width = 0.1) +
  scale_fill_manual(values = cmap_category) +
  # scale_color_manual(values = cmap_category) +
  facet_grid(. ~ category, space = "free_x", scales = "free_x") +
  theme(strip.background = element_blank(),
        axis.text.x = element_text(size = 9)) +
  rotate_x() +
  ylab("Mean predicted log-counts for AB") +
  ggtitle("Distribution of predicted counts for all spacings/orientations of each comp. motif") +
  no_legend()