---
title: "Supplemental file: R-code"
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Beyond the wiretap: criminal activity networks in court cases built on captured encrypted data 

This R Markdown document contains only the code for the paper "Beyond the wiretap: criminal activity networks in court cases built on captured encrypted data" since the data for this study cannot be shared due to legal and ethical restrictions.

It contains the regular expressions (regex) coding the court case documents and the code used to produce the output in the main article. 


```{r libraries, eval = FALSE}
#Packages used
library(tidyverse) # ggplot2, dplyr, etc.
library(openxlsx)  # import/write Excel-files
library(xts)
library(igraph)    # network analyses
library(tidygraph) # tidy interface to igraph
library(ggraph)    # network plots
library(patchwork) # plots management
library(pdftools)  # pdf to txt
library(readr)
library(stringr)

```


## Coding court case documents

Function to convert from .pdf to .txt: 

```{r, eval = FALSE}

# Function to convert PDFs to text files
convert_pdfs_to_txt <- function(source_dir, target_dir) {
  # Ensure the target directory exists, create it if it doesn't
  if (!dir.exists(target_dir)) {
    dir.create(target_dir, recursive = TRUE)
  }
  
  # List all PDF files in the source directory
  pdf_files <- list.files(source_dir, pattern = "\\.pdf$", full.names = TRUE)
  
  # Iterate over each PDF file
  for (pdf_file in pdf_files) {
    # Extract text from PDF
    text <- pdf_text(pdf_file)
    
    # Create a new filename with .txt extension
    txt_filename <- paste0(target_dir, "/", 
                           basename(tools::file_path_sans_ext(pdf_file)), ".txt")
    
    # Write text to new file
    writeLines(text, txt_filename)
  }
  
  cat("Conversion completed. Text files saved to:", target_dir)
}


```

Converting the files: 

```{r, eval = FALSE}
 convert_pdfs_to_txt(
   "NAME/OF/THE/SOURCE/DIRECTORY",  #Source folder containing pdf files
   "NAME/OF/THE/TARGET/DIRECTORY")  #Target folder where txt files will be stored 
```

Store an object in R with the file names in the target folder:

```{r, eval = FALSE}
file_paths <- list.files(
  "NAME/OF/THE/TARGET/DIRECTORY",
  full.names = TRUE,  # The entire directory
  pattern = "\\.txt$" # Retrieve files ending with ".txt"
)
```

The following code scrapes the court case documents now saved as text files (above), taking advantage of nearly all court cases having the same document structure:   

```{r, eval = FALSE}
##############################
## 1. Case-level Helpers
##############################
extract_court_name <- function(lines) {
  pattern <- "([A-Za-zÅÄÖåäö]+(?:[ '-][A-Za-zÅÄÖåäö]+)*)\\s*tingsrätt\\W?"
  for (line in lines) {
    if (grepl(pattern, line, ignore.case = TRUE)) {
      matches <- regmatches(line, regexec(pattern, line, ignore.case = TRUE))
      if (length(matches) > 0 && length(matches[[1]]) > 1) {
        return(matches[[1]][2])  # e.g. "Stockholms"
      }
    }
  }
  # Second pass: lines where "tingsrätt" (district court) stands alone
  tingsratt_only_pattern <- "^\\s*tingsrätt\\W?\\s*$"
  for (i in seq_along(lines)) {
    if (grepl(tingsratt_only_pattern, lines[i], ignore.case = TRUE) && i > 1) {
      combined_line <- paste(lines[i - 1], "tingsrätt")
      matches <- regmatches(combined_line, 
                            regexec(pattern, combined_line, ignore.case = TRUE))
      if (length(matches) > 0 && length(matches[[1]]) > 1) {
        return(matches[[1]][2])
      }
    }
  }
  return(NA)
}

extract_info_with_fallback <- function(lines, pattern, is_numeric = FALSE) {
  matches <- regmatches(lines, regexec(pattern, lines))
  info <- sapply(matches, function(x) if (length(x) > 1) x[2] else NA)
  info <- na.omit(info)
  if (length(info) > 0) {
    return(if (is_numeric) as.integer(info[1]) else info[1])
  }
  return(NA)
}

extract_case_number <- function(lines) {
  b_pattern <- "B\\s*\\d+-\\d+"
  manummer_idxs <- grep("Målnummer", lines, ignore.case = TRUE) 
  if (length(manummer_idxs) > 0) {
    for (idx in manummer_idxs) {
      search_range <- seq(idx + 1, min(idx + 5, length(lines)))
      for (j in search_range) {
        found_pos <- regexpr(b_pattern, lines[j], ignore.case = TRUE)
        if (found_pos[1] != -1) {
          return(regmatches(lines[j], found_pos))
        }
      }
    }
  }
  fallback_pattern <- "Mål\\s+nr:?\\s+(B\\s*\\d+-\\d+)"
  return(extract_info_with_fallback(lines, fallback_pattern))
}

extract_num_defendants <- function(lines) {
  pattern1 <- "Tilltalade\\s+(\\d+)\\s+st"
  n1 <- extract_info_with_fallback(lines, pattern1, is_numeric = TRUE)
  if (!is.na(n1)) return(n1)

  pattern2 <- "PARTER\\s*\\(\\s*Antal\\s+tilltalade:\\s*(\\d+)\\s*\\)"
  n2 <- extract_info_with_fallback(lines, pattern2, is_numeric = TRUE)
  if (!is.na(n2)) return(n2)

  tiltalad_indices <- grep("^\\s*Tilltalad\\b", lines, ignore.case = TRUE)
  if (length(tiltalad_indices) > 0) {
    return(length(tiltalad_indices))
  }
  return(NA)
}


##############################
## 2. Platform Checker
##############################

check_platform <- function(lines) {
  # Combine entire text
  all_text <- paste(lines, collapse = " ")

  # Patterns for each platform
  encrochat_words <- c("EncroChat", "Encrochat", "Encrotelefon", "Encro",
                       "Encrochatenheter", "encrochat", "Encrochattelefon",
                       "encrochattelefon", "Encrochat-telefon", "Encro-telefoner",
                       "EncroChat-", "encrotelefon")
  encro_pattern <- paste(encrochat_words, collapse = "|")

  anom_words <- c("Anom-", "Anom", "Anom-telefonen", "Anom-telefon", "Anom-telefoner")
  anom_pattern <- paste(anom_words, collapse = "|")

  sky_words <- c("SkyECC-", "SkyECC", "SkyECC:", "Sky-", "Sky-telefoner", 
                 "Sky ECC", "SKY-telefon", "Sky-telefon", "SKY ECC", "SKY") 
  sky_pattern <- paste(sky_words, collapse = "|")

  # Term Frequency (TF): count how many times each platform is mentioned 
  # in the court case (case-insensitive)
  encro_count <- str_count(all_text, regex(encro_pattern, ignore_case = TRUE))
  anom_count  <- str_count(all_text, regex(anom_pattern,  ignore_case = TRUE))
  sky_count   <- str_count(all_text, regex(sky_pattern,   ignore_case = TRUE))

  # Determine which platforms
  found <- c()
  if (encro_count > 0) found <- c(found, "EncroChat")
  if (anom_count  > 0) found <- c(found, "Anom")
  if (sky_count   > 0) found <- c(found, "SkyECC")

  platform_str <- if (length(found) > 0) paste(found, collapse = ", ") else NA

  list(
    Platform       = platform_str,
    EncroChat_TF   = encro_count,
    Anom_TF        = anom_count,
    SkyECC_TF      = sky_count
  )
}


##############################
## 3. Sub-Block Parsers (row-specific) for Crimes & Sentence
##############################

extract_crimes_in_subblock <- function(subblock) {
  start_pattern <- "^\\s*Brott som .* döms för$"
  end_pattern   <- 
    "Påföljd\\b|Påföljd\\s*m\\.m\\.|Åtal som avvisas|Åtal som .* frikänns från"
  
  all_crimes <- character(0)
  i <- 1
  while (i <= length(subblock)) {
    if (grepl(start_pattern, subblock[i], ignore.case = TRUE)) {
      j <- i + 1
      while (j <= length(subblock) && !grepl(end_pattern, subblock[j], 
                                             ignore.case = TRUE)) {
        all_crimes <- c(all_crimes, subblock[j])
        j <- j + 1
      }
      i <- j
    } else {
      i <- i + 1
    }
  }
  all_crimes <- trimws(all_crimes)
  all_crimes <- all_crimes[nzchar(all_crimes)]
  if (length(all_crimes) == 0) return(NA_character_)
  
  return(paste(all_crimes, collapse = "; "))
}

extract_sentence_in_subblock <- function(subblock) {
  pat <- "^\\s*Påföljd(\\s*m\\.m\\.)?\\b"
  p_index <- grep(pat, subblock, ignore.case = TRUE)
  if (length(p_index) == 0) return(NA_character_)
  idx <- p_index[1]
  if (idx < length(subblock)) {
    return(trimws(subblock[idx + 1]))
  }
  return(NA_character_)
}

parse_subblock_for_crimes_sentence <- function(subblock) {
  crimes   <- extract_crimes_in_subblock(subblock)
  sentence <- extract_sentence_in_subblock(subblock)
  list(crimes = crimes, sentence = sentence)
}


##############################
## 4. The Block Parser (row by SSN)
##############################
extract_row_per_ssn <- function(block) {
  ssn_pattern <- "\\b(19|20)\\d{6}[- ]?\\d{4}\\b"
  
  block_len <- length(block)
  ssn_line_indices <- which(sapply(block, function(x) grepl(ssn_pattern, x)))
  if (length(ssn_line_indices) == 0) {
    return(data.frame(
      SSN = NA_character_,
      Address = NA_character_,
      CrimesInfo = NA_character_,
      SentenceInfo = NA_character_,
      stringsAsFactors = FALSE
    ))
  }
  
  results <- list()
  for (i in seq_along(ssn_line_indices)) {
    start_idx <- ssn_line_indices[i]
    end_idx <- if (i < length(ssn_line_indices)) {
      ssn_line_indices[i+1] - 1
    } else {
      block_len
    }
    subblock <- block[start_idx:end_idx]
    
    found_ssns <- regmatches(block[start_idx],
                             gregexpr(ssn_pattern, block[start_idx]))[[1]]
    address <- gather_address_lines(block, start_idx, end_idx)
    cs <- parse_subblock_for_crimes_sentence(subblock)
    
    for (this_ssn in found_ssns) {
      results[[length(results)+1]] <- data.frame(
        SSN           = this_ssn,
        Address       = address,
        CrimesInfo    = cs$crimes,
        SentenceInfo  = cs$sentence,
        stringsAsFactors = FALSE
      )
    }
  }
  
  out <- do.call(rbind, results)
  rownames(out) <- NULL
  return(out)
}

gather_address_lines <- function(block, ssn_idx, subblock_end) {
  defense_end <- "^\\s*Offentlig försvarare\\b|^\\s*Offentlig försvarare:|^\\s*Offentlig försvarare genom substitution|^\\s*Åklagare\\b"
  ssn_pattern <- "\\b(19|20)\\d{6}[- ]?\\d{4}\\b"
  
  address_lines <- character(0)
  j <- ssn_idx + 1
  while (j <= subblock_end) {
    if (grepl(ssn_pattern, block[j])) break
    if (grepl(defense_end, block[j], ignore.case = TRUE)) break
    address_lines <- c(address_lines, block[j])
    j <- j + 1
  }
  
  address_lines <- trimws(address_lines)
  address_lines <- address_lines[nzchar(address_lines)]
  if (length(address_lines) == 0) {
    return(NA_character_)
  } else {
    return(paste(address_lines, collapse = "; "))
  }
}

parse_defendant_block <- function(block) {
  df_rows <- extract_row_per_ssn(block)
  return(df_rows)
}


##############################
## 5. Identify Defendant ["Tilltalad"] Blocks
##############################
extract_all_defendant_blocks <- function(lines) {
  tiltalad_indices <- grep("^\\s*Tilltalad\\b", lines, ignore.case = TRUE)
  
  if (length(tiltalad_indices) == 0) {
    return(data.frame(
      SSN = NA_character_, 
      Address = NA_character_,
      CrimesInfo = NA_character_,
      SentenceInfo = NA_character_,
      stringsAsFactors = FALSE
    ))
  }
  
  tiltalad_text <- lines[tiltalad_indices]
  tiltalad_text_clean <- tolower(trimws(tiltalad_text))
  unique_mask <- !duplicated(tiltalad_text_clean)
  tiltalad_indices <- tiltalad_indices[unique_mask]
  
  block_list <- list()
  for (i in seq_along(tiltalad_indices)) {
    start_idx <- tiltalad_indices[i]
    end_idx <- if (i < length(tiltalad_indices)) {
      tiltalad_indices[i + 1] - 1
    } else {
      length(lines)
    }
    block <- lines[start_idx:end_idx]
    
    df_block <- parse_defendant_block(block)
    block_list[[i]] <- df_block
  }
  
  out_df <- do.call(rbind, block_list)
  rownames(out_df) <- NULL
  return(out_df)
}


##############################
## 6. Main Function
##############################
extract_case_details2 <- function(file_path) {
  lines <- readLines(file_path, warn = FALSE, encoding = "UTF-8")

  # 1) Basic case-level data
  file_name      <- basename(file_path)
  court_name     <- as.character(extract_court_name(lines))
  case_number    <- as.character(extract_case_number(lines))
  
  date_pattern   <- "\\b\\d{4}-\\d{2}-\\d{2}\\b"
  date_matches   <- unlist(regmatches(lines, gregexpr(date_pattern, lines)))
  date           <- if (length(date_matches) > 0) date_matches[1] else NA_character_
  
  num_defendants <- as.integer(extract_num_defendants(lines))

  # 2) Platform Info
  platform_info <- check_platform(lines)

  # 3) Defendant blocks -> row per SSN
  df_defendants <- extract_all_defendant_blocks(lines)

  # 4) Combine into final data frame
  n <- nrow(df_defendants)
  df_out <- data.frame(
    FileName      = rep(file_name,      n),
    CourtName     = rep(court_name,     n),
    CaseNumber    = rep(case_number,    n),
    Date          = rep(date,           n),
    NumDefendants = rep(num_defendants, n),
    SSN           = df_defendants$SSN,
    Address       = df_defendants$Address,
    CrimesInfo    = df_defendants$CrimesInfo,
    SentenceInfo  = df_defendants$SentenceInfo,
    Platform       = rep(platform_info$Platform,       n),
    EncroChat_TF   = rep(platform_info$EncroChat_TF,   n),
    Anom_TF        = rep(platform_info$Anom_TF,        n),
    SkyECC_TF      = rep(platform_info$SkyECC_TF,      n),
    
    stringsAsFactors = FALSE
  )

  # 5) Deduplicate SSNs if needed
  df_out <- df_out[!duplicated(df_out[c("CaseNumber", "SSN")]), ]

  return(df_out)
}
```

Combining the file paths and the function above creates a data frame. The data has been manually checked to ensure reliability since not all court case documents have the exact same structure: 

```{r, eval = FALSE}
df <- map(file_paths,
          extract_case_details2) %>%
  list_rbind()
```


## Fig. 1: Type of crimes

Figure 1 illustrates the distribution of crime types for each platform (Anom, EncroChat, and SkyECC), also compared to official statistics from the judicial system (source: the Swedish National Council for Crime Prevention [BRÅ]: https://bra.se/statistik/statistik-om-rattsvasendet/personer-lagforda-for-brott, "Lagföringsbeslut efter huvudbrott och huvudpåföljd").

First the official statistics, then the code for figure 1.

### Fig. 1: Official statistics

Import and wrangle the data: 
```{r, eval = FALSE}

#Import
brå18 <- read.xlsx("/DIRECTORY/420La-2018.xlsx", # Directory
                   sheet = "Prepared",           # Information from the pre-wrangled sheet
                   colNames = T)                 # Retains column names

#Adding a percentage column
brå18 <- brå18 %>%
  mutate(Prison_percentage = 
           round((Fängelse / sum(Fängelse))*100,1))

# Keeping all categories found in the court case material
brå18 <- brå18 %>%
  filter(Huvudbrott %in% c(            
 "3 kap. Brott mot liv och hälsa",                             
 "4 kap. Brott mot frihet och frid",                           
 #"5 kap. Ärekränkning"                           
 #"6 kap. Sexualbrott"                                         
 #"7 kap. Brott mot familj"                                    
 "8 kap. Tillgreppsbrott",                                     
 "9 kap. Bedrägeri och annan oredlighet"  ,                    
 "10 kap. Förskingring, annan trolöshet och mutbrott"  ,       
 "11 kap. Brott mot borgenärer m.m."   ,                       
# "12 kap. Skadegörelsebrott", Placing in category "Other" due to small N               
 "13 kap. Allmänfarliga brott"   ,                             
 "14 kap. Förfalskningsbrott"  ,                               
# "15 kap. Mened, falskt åtal m.m."                            
 "16 kap. Brott mot allmän ordning",                          
 "17 kap. Brott mot allmän verksamhet"  ,                      
 #"19 kap. Brott mot Sveriges säkerhet"                        
 #"20 kap. Tjänstefel m.m."                                    
 "Brott mot trafikbrottslagen" ,                               
 "Brott mot narkotikastrafflagen",                             
 #"Brott mot skattebrottslagen"                                
 "Vapenlag, 9 kap.",                                           
 "Lag om straff för smuggling",                                
# "Lag om straff för marknadsmissbruk på värdepappersmarknaden"
 "Bidragsbottslag", # SIC                                        
 "Lag om straff för penningtvättsbrott",                       
 #"Sjölag"                                                     
 "Lag om förbud mot vissa dopningsmedel",                      
# "Alkohollag"                                                 
# "Lag om totalförsvarsplikt"                                  
# "Jaktlag/-förordning"                                        
 "Utlänningslag",                                              
 "Lag om förbud betr. knivar m.m.",                            
# "Lag om kontaktförbud"                                       
# "Aktiebolagslag "                                            
 "Lag om brandfarliga och explosiva varor"                    
# "Lag om tillträdesförbud i butik"                            
# "Övriga författningar"                
  )
) %>%
  mutate(
    #Combining drugs and doping:
    Huvudbrott = case_when(
      Huvudbrott %in% c("Brott mot narkotikastrafflagen",
                        "Lag om förbud mot vissa dopningsmedel") ~ "Drugs",
    #Combining firearms and knives:
    Huvudbrott %in% c("Vapenlag, 9 kap.",
                      "Lag om förbud betr. knivar m.m.") ~ "Weapons",
    #Combining fraud, bribe and offence against creditor
    Huvudbrott %in% c(
      "9 kap. Bedrägeri och annan oredlighet"  ,                    
      "10 kap. Förskingring, annan trolöshet och mutbrott"  ,       
      "11 kap. Brott mot borgenärer m.m.",
      "Bidragsbottslag",
      "14 kap. Förfalskningsbrott") ~ "Fraud",
    # Defining the "Other" category
    Huvudbrott %in% c(
      "Utlänningslag",
      "16 kap. Brott mot allmän ordning",
      "12 kap. Skadegörelsebrott"
    ) ~ "Other",
    TRUE ~ Huvudbrott,
  ),
  #Recoding the names of each crime category
  Huvudbrott = recode(Huvudbrott,
 "3 kap. Brott mot liv och hälsa" = "Violence",                            
 "4 kap. Brott mot frihet och frid" = "Kidnapping_threat",                           
 "8 kap. Tillgreppsbrott" = "Theft_robbery",                                     
 "12 kap. Skadegörelsebrott" = "Damage" ,                            
 "13 kap. Allmänfarliga brott" = "Public_danger",                             
 "17 kap. Brott mot allmän verksamhet" = "Public_activity" ,                      
 "Brott mot trafikbrottslagen" = "Traffic" ,                               
 "Lag om straff för smuggling" = "Trafficking",                                
 "Lag om straff för penningtvättsbrott" = "Money_laundering",                       
 "Lag om brandfarliga och explosiva varor"  =  "Explosives"
  )
  )


# Adding values/percentages per crime type to get distinct crime category figures
brå18 <- brå18 %>%
group_by(Huvudbrott) %>%
  summarise(
    Prison = sum(Fängelse, na.rm = TRUE),
    Prison_percentage = sum(Prison_percentage, na.rm = TRUE),
    .groups = "drop"
  )

```

### Fig 1. Plot

Preparing the plot by first categorising the crime types. In the chunk below are all the crimes found in the sentences, coded according to the swedish penal law (following the BRÅ-data above). See a Swedish-English dictionary provided by the Swedish Police Authority: https://polisen.se/siteassets/dokument/om-polisen/sprakvard/svensk-engelsk-ordlista.pdf/download/?v=077732bde6b8423076de89c9d75bb5db

```{r, eval = FALSE}
#DRUGS: "Brott mot narkotikastrafflagen (1968:64)"
  # Note1: DOPINGSBROTT is found in "Lag (1991:1969) om förbud mot vissa dopningsmedel" 
  # but is included under "Drugs" here.
  # Note2: Coding only paragraph, what discerns some is the "punkt" (p). 
Drugs <- c("Dopningsbrott", # 2§ 6p och 3§ 2 st.
           "Förberedelse till grovt narkotikabrott", # 1§ 1 st 4 p, 3§ 1 st och 4§ 1 st
           "Försök till grovt narkotikabrott", # 1§ 1 st 3 p och 4 p, 3§ 1 st och 4§ 1 st
           "Försök till narkotikabrott", # 1§ 4§
           "Försök till synnerligen grovt narkotikabrott", # 1§ 3§ 4§
           "Grovt narkotikabrott",  # 1§ 3§
           "Medhjälp till grovt narkotikabrott", # 1§ 3§ 5§
           "Medhjälp till narkotikabrott", # 1§ 5§
           "Medhjälp till synnerligen grovt narkotikabrott", # 1§ 3§ 5§ + 23 kap 4§ BrB
           "Narkotikabrott",  # 1§
           "Ringa narkotikabrott", # 1§ 2§
           "Stämpling till grovt narkotikabrott",  #1§ 3§ 4§ + 23 kap 2§ BrB
           "Stämpling till synnerligen grovt narkotikabrott", # 1§ 3§ 4§ + 23 kap 2§ BeB
           "Synnerligen grovt narkotikabrott"  ) # 1§ 3§

#DRUG TRAFFICKING: Lag (2000:1225) om straff för smuggling
Trafficking <- c(
  "Försök till grov narkotikasmuggling", # 3§ 6§ 14§ + 23 kap 1§ BrB
  "Försök till synnerligen grov narkotikasmuggling", # 3§ 6§ 14§ + 23 kap 1§ BrB
  "Grov narkotikasmuggling", # 3§ 6§
  "Medhjälp till grov narkotikasmuggling", # 3§ 6§ + 23 kap  4§ BrB
  "Medhjälp till synnerligen grov narkotikasmuggling", # 3§ 6§ + 23 kap  4§ BrB
  "Synnerligen grov narkotikasmuggling" # 3§ 6§
)


# ~~~~~~~~~~~~~ BROTTSBALKEN, BrB  ~~~~~~~~~~~~~ 
#VIOLENCE: 3 kap BrB "Brott mot liv och hälsa"
Violence <- c(
  "Anstiftan av försök till mord", # 1§ 11§ + 23 kap 1§ 4§
  "Anstiftan av mord", # 1§ 5§ + 23 kap 4§
  "Framkallande av fara för annan", # 9§
  "Förberedelse till mord", # 1§ 11§ + 23 kap 2§
  "Försök till grov misshandel", # 6§ 11§ + 23 kap 1§
  "Försök till misshandel", # 5§ 11§ + 23 kap 1§
  "Försök till mord", # 1§ 11§ + 23 kap 1§
  "Grov misshandel",  # 6§
  "Medhjälp till förberedelse till mord", # 1§ 11§ + 23 kap 2§ 4§
  "Medhjälp till försök till grov misshandel", # 6§ 11§ + 23 kap 1§ 4§ 
  "Medhjälp till försök till mord", # 1§ 11§ + 23 kap 1§ 4§
  "Medhjälp till grov misshandel", # 6§ + 23 kap 4§
  "Medhjälp till mord", # 1§ + 23 kap 4§
  "Misshandel", # 5§
  "Mord", # 1§
  "Stämpling till mord", # 1§ 11§ + 23 kap 2§
  "Stämpling till synnerligen grov misshandel",  # 6§ 11§ + 23 kap 2§
 "Synnerligen grov misshandel", # 6§
 "Vållande till kroppsskada" # 8§
 )

# 4 kap BrB "Brott mot frihet och frid"/"Offence against liberty and peace" 
Kidnapping_threat <- c(
   "Förberedelse till människorov",  # 1§ 10§ + 23 kap 2§
   "Medhjälp till människorov", # 1§ + 23 kap 4§
   "Människorov", # 1§
   "Stämpling till människorov", # 1§ 10§ + 23 kap 2§
   "Grovt olaga hot" , # 5§
   "Olaga hot" # 5§
   )

# 8 kap BrB: "Tillgreppsbrott" : "Appropriative offence"
Theft_robbery <- c(
  "Försök till tillgrepp av fortskaffningsmedel", # 7§ 12§ + 23 kap 1§
  "Grovt rån", # 6§
  "Medhjälp till rån", # 5§ + 23 kap 4§
  "Ringa stöld", # 2§
  "Rån", # 5§
  "Stämpling till rån"  # 5§ 12§ + 23 kap 2§
  )

# 9 kap BrB: "Bedrägeri och annan oredlighet" : "Fraud and other dishonesty"
  # NOTE: Adding 10 kap (Embezzlement,bribe) and 11 kap (creditors) since they only have 1 crime category, resp. as well as benefit crime (Bidragsbrott) and Falsification (Urkundsbrott)
Fraud <- c(
  "Försök till grov utpressning", # 4§ 11§ + 23 kap 1§
  "Grov utpressning", # 4§
  "Grovt bedrägeri", # 3§
  "Grovt bedrägeri medelst brukande av falsk urkund", # 3§ + 14 kap 1§ 10§ 
  "Medhjälp till försök till grov utpressning", # 4§ 11§ + 23 kap 1§ 4§
  "Medhjälp till grovt bedrägeri medelst brukande av falsk urkund", # 3§ + 14 kap 1§ 10§ + 23 kap 4§ 
  "Grovt häleri", # 6§
   "Olovligt brukande", #10 kap BrB: "Förskingring, annan trolöshet och mutbrott": "Embezzlement, .. bribe"
  "Grovt bokföringsbrott", # 11 kap BrB: "Brott mot borgenärer m.m." : "offence against creditors"
  "Bidragsbrott", # 2§ Bidragsbrottslagen, (2007:612)
  "Förberedelse till urkundsförfalskning", # 1§ 13§ + 23 kap 2§ 14 kap BrB: "Förfalskningsbrott" :
   "Urkundsförfalskning" # 1§ 14 kap BrB: "Förfalskningsbrott" :
)

# 13 kap BrB: "Allmänfarliga brott" : "Public danger offence"
Public_danger <- c(
  "Allmänfarlig ödeläggelse", # 3§
  "Anstiftan av allmänfarlig ödeläggelse", # 3§ + 23 kap 4§
  "Förberedelse till allmänfarlig ödeläggelse", # 3§ 12§ + 23 kap 2§
  "Försök till allmänfarlig ödeläggelse", # 3§ 12§ + 23 kap 1§
  "Medhjälp till allmänfarlig ödeläggelse", # 3§ + 23 kap 4§ 
  "Medhjälp till förberedelse till allmänfarlig ödeläggelse", # 3§ 12§ + 23 2§ 4§§
  "Medhjälp till försök till allmänfarlig ödeläggelse", # 3§ 12§ + 23 kap 1§ 4§
  "Stämpling till allmänfarlig ödeläggelse", # 3§ 12§ + 23 kap 2§
  "Sabotage mot blåljusverksamhet" # 5c§
)

# 17 kap BrB: "Brott mot allmän verksamhet" : "offence against public activity"
Public_activity <- c(
  "Anstiftan av skyddande av brottsling", # 11§ + 23 kap 4§
  "Hot mot tjänsteman", # 1§
  "Skyddande av brottsling", # 11§
  "Våld mot tjänsteman", # 1§ 5§
  "Försök till våld mot tjänsteman", # 1§ 5§ 16§ + 23 kap 1§
  "Våldsamt motstånd"  # 4§ 5§
  ) 


# ~~~~~~~~~~~~~~~~~~~~~~~~~~ 

# MONEY LAUNDERING: Lag (2014:307) om straff för penningtvättsbrott
# Financial <- c()
Money_laundering <- c(
  "Anstiftan av grovt penningtvättsbrott", # 3§ 5§ + 23 kap 4§
  "Grovt penningtvättsbrott", # 3§ 5§
  "Medhjälp till grovt penningtvättsbrott", # 3§ 5§ + 23 kap 4§
  "Näringspenningtvätt", #  7§ NOTERA: finns Grovt (2 st) resp. Ringa (3 st)
  "Penningtvättsbrott", # 3§
 "Penningtvättsförseelse" # 6§
 )


# Vapenlagen (1996:67), 9 kap:
  # NOTE: Also including knifes here
Weapons <- c(
  "Anstiftan av grovt vapenbrott", # 1a§ 
  "Brott mot lagen om förbud beträffande knivar och andra farliga föremål", # 1§ 4§
  "Brott mot vapenlagen",  # 2§
  "Försök till grovt vapenbrott", # 1a§ 8§ + 23 kap 1§
  "Grovt vapenbrott", # 1a§
  "Medhjälp till försök till grovt vapenbrott", # 1a§ 8§ + 23 kap 1§ 4§
  "Medhjälp till grovt vapenbrott", # 1a§ + 23 kap 4§
  "Synnerligen grovt vapenbrott", # 1a§
  "Vapenbrott"  # 1§
  )

# Brott mot lagen om brandfarliga och explosiva varor (2010:1011)
Explosives <- c(
   "Brott mot lagen om brandfarliga och explosiva varor" # 29a§ 
)


# GATHERING VARIOUS TRAFFIC RELATED OFFENCES FROM DIFFERENT LEGISLATIONS
Traffic <- c(
  "Brott mot fordonsförordningen", # Brott mot fordonsförordningen (2009:211), 8 kap: 9§ 11§
  "Brott mot trafikförordningen", # 4 kap 9 § 14 kap 3 §  trafikförordningen; (1998:1276)
  "Grov vårdslöshet i trafik", #1 § 2 st trafikbrottslagen (1951:649)
  "Grovt rattfylleri", # 4 § 2 st och 4 a § trafikbrottslagen (1951:649)
  "Hastighetsöverträdelse", #3 kap 17 § 2 st och 14 kap 3 § 1 p b trafikförordningen; (1998:1276)
  "Olovlig körning", #  3 § 1 st 2 men trafikbrottslagen (1951:649)
  "Rattfylleri", # 4 § 2 st trafikbrottslagen (1951:649)
  "Vårdslöshet i trafik" # 1 § 1 st trafikbrottslagen (1951:649) 
  )

Other <- c(
  "Brott mot utlänningslagen",# 20 kap 2 § utlänningslagen (2005:716)
  "Brott mot yppandeförbud", #9 kap 6 § och 23 kap 10 § 7 st rättegångsbalken (1942:740)
  "Brott som bedöms ingå i ett annat brott",
  "Våldsamt upplopp", # 2§ 16 kap BrB: "Brott mot allmän ordning": "offence against public order"
  "Barnpornografibrott", # 10a§ 16 kap BrB: "Brott mot allmän ordning": "offence against public order"
  "Folkbokföringsbrott",   # 25§ 42§ Folkbokföringslagen (1991:481)
  "Anstiftan av grov skadegörelse", # 3§ + 23 kap 4§
  "Skadegörelse" # 1§
)
  


```


Creating a long format data frame for Figure 1 and adding columns:
```{r, eval = FALSE}

#Long format
df_long <- df %>%
  select(FileName, Date, Platform, Crime1:Crime14) %>% 
  select(!ends_with("_date")) %>%
  pivot_longer(
    cols = starts_with("Crime"),   # e.g. Crime1:Crime14
    names_to = "CrimeIndex",       # e.g. "Crime1", "Crime2", ...
    values_to = "Crime",           # the actual crime text
    values_drop_na = TRUE          # optionally drop rows where the crime is NA
  )


#Adding a column to the data with the overarching crime category:
df_long <- df_long %>%
  mutate(
    CrimeCategory = case_when(
      Crime %in% Drugs ~ "Drugs",
      Crime %in% Explosives ~ "Explosives",
      Crime %in% Fraud ~ "Fraud",
      Crime %in% Kidnapping_threat ~ "Kidnapping_threat",
      Crime %in% Money_laundering ~ "Money_laundering",
      Crime %in% Other ~ "Other",
      Crime %in% Public_activity ~ "Public_activity",
      Crime %in% Public_danger ~ "Public_danger",
      Crime %in% Theft_robbery ~ "Theft_robbery",
      Crime %in% Traffic ~ "Traffic",
      Crime %in% Trafficking ~ "Trafficking",
      Crime %in% Violence ~ "Violence",
      Crime %in% Weapons ~ "Weapons"
    )
  )

# Adjusting the DATE variable for development (further below)
  df_long <- df_long %>%
  mutate(Date = as.Date(Date),
         Month = as.yearmon(Date),
         Quart = as.yearqtr(Date),
         Year = as.numeric(format(Date, "%Y")))
  
#Splitting the PLATFORMS into SINGLE categories
  df_long <- df_long %>%
  # 1) Split the 'Platform' column into a list of platforms
  mutate(Platform_list = str_split(Platform, ",\\s*")) %>%
  # 2) Unnest, creating one row per platform in the list
  unnest(cols = c(Platform_list)) %>%
  # 3) Rename for clarity
  rename(Platform_single = Platform_list)

  # Creating a data frame for development (further below)
  df_long2 <- df_long %>%
  group_by(Year, CrimeCategory, Platform_single) %>%
  summarise(
    n = n_distinct(FileName),   # how many unique cases
    .groups = "drop"
  )
  
```

Figure 1: distribution of crime categories across platform (single) and BRÅ-data from 2018:

```{r, eval = FALSE}

#Defining colurblind-friendly palette:
cbbPalette <- c("#000000", "#E69F00", "#56B4E9")
  
# Figure 1
gg_figure1 <- df_long %>%
  group_by(Platform_single) %>%
  count(CrimeCategory) %>%
  mutate(Percent = n / sum(n) * 100) %>%  # Fixed: percent within each platform
  mutate(CrimeCategory = fct_reorder(CrimeCategory, Percent, .desc = TRUE)) %>%
  ggplot(aes(x = CrimeCategory, y = Percent, fill = Platform_single)) + 
  geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
  theme_minimal() +
  xlab("Crime category") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        legend.position = "bottom") +
  ylim(0, 80)+
  scale_fill_manual(values=cbbPalette)+
  labs(fill = "Platform:")+
  scale_x_discrete(labels = c("Money_laundering" = "Money laundering",
                              "Trafficking" = "Drug trafficking",
                              "Public_activity" = "Public activity",
                              "Public_danger" = "Public danger",
                              "Theft_robbery" = "Theft/robbery",
                              "Kidnapping_threat" = "Kidnapping/threat"))+
  
  #Adding the BRÅ-data
  geom_point(data = brå18, aes(Huvudbrott, Prison_percentage), 
             size = 2,
            inherit.aes = FALSE)

print(gg_figure1)
```

Chi-square test:

```{r, eval = FALSE}
# Contingency table (rows = platforms, cols = crime types)
count_matrix <- xtabs(n ~ Platform_single + CrimeCategory, data = count_df)

#For reproducibility
set.seed(42) 
# Chi-square test with Monte Carlo simulations
chi_full <- chisq.test(count_matrix, simulate.p.value = TRUE, B = 10000)

#Standardised residuals in table 2
stdres <- round(chi_full$stdres, 2)
```



# Fig. 2: Development of court cases
Next we look closer at the number of court cases per platform, per year, for the five most common crime categories:
Drugs, weapons, violence, money laundering and drug trafficking. Together, these comprise 87% of all the charges (1708 / 1952) extensively counted (recall: a case with all platforms equals 3 cases).


```{r, eval = FALSE}
# Order the five crime categories by their max counts
crime_order <- df_long2 %>%
  filter(CrimeCategory %in% c("Drugs","Weapons","Violence","Money_laundering","Trafficking")) %>%
  group_by(CrimeCategory) %>%
  summarise(MaxN = max(n, na.rm = TRUE), .groups = "drop") %>%
  arrange(desc(MaxN)) %>%
  pull(CrimeCategory)

# Build the "overall cases" panel data so it matches columns
# Creating a data frame without "CrimeX_date" to simplify
df2 <- df %>%
  # 1) Split the 'Platform' column into a list of platforms
  mutate(Platform_list = str_split(Platform, ",\\s*")) %>%
  # 2) Unnest, creating one row per platform in the list
  unnest(cols = c(Platform_list)) %>%
  # 3) Rename for clarity
  rename(Platform_single = Platform_list)

 df2.2 <- df2 %>% 
   mutate(DateY = year(Date)) %>%
  group_by(CaseNumber, DateY) %>%
   mutate(mean_months = mean(TotalMonths, na.rm =T)) %>%
  select(Date, DateY, CaseNumber, TotalMonths, mean_months, Platform, Platform_single) %>%
  ungroup()

overall_cases <- df2.2 %>%
  distinct(CaseNumber, Platform_single, .keep_all = TRUE) %>%
  count(Year = DateY, Platform_single, name = "n") %>%   # align col names
  mutate(CrimeCategory = "Overall cases")

# Build the five-facet data and standardize columns
crime_panels <- df_long2 %>%
  filter(CrimeCategory %in% crime_order) %>%
  transmute(Year, n, Platform_single, CrimeCategory)

# Combine and set facet order (overall first, then the rest)
plot_dat <- bind_rows(overall_cases, crime_panels) %>%
  mutate(
    CrimeCategory = factor(
      CrimeCategory,
      levels = c("Overall cases", crime_order)   # ensures upper-left placement
    )
  )

```

The following code produces figure 2:
```{r, eval = FALSE}

# One plot with six facets; "Overall cases" at upper-left
gg_figure2 <- ggplot(plot_dat, aes(x = Year, y = n, color = Platform_single)) +
  geom_line() +
  geom_point() +
  facet_wrap(~ CrimeCategory, scales = "free_y", ncol = 3,  # 2 rows x 3 cols
             labeller = as_labeller(c(
               `Overall cases` = "Overall cases",
               Drugs = "Drugs",
               Weapons = "Weapons",
               Violence = "Violence",
               Trafficking = "Drug trafficking",
               Money_laundering = "Money laundering"
             ))) + 
  theme_bw() +
  labs(
    x = "Year",
    y = "Number of Court Cases",
    color = "Platform"
  ) +
  scale_colour_manual(
    values = cbbPalette,
    breaks = c("Anom", "EncroChat", "SkyECC"),
    labels = c("Anom (n=58)", "EncroChat (n=95)", "SkyECC (n=74)")
  ) +
  theme(legend.position = "bottom")

print(gg_figure2)
```


# Fig. 3: Development of mean sentence length

This code produces the mean sentence length across time for each platform. 

Creating similar data frames as above but with other names for clarity
```{r, eval = FALSE}
df_sent <- df %>%
  # 1) Split the 'Platform' column into a list of platforms
  mutate(Platform_list = str_split(Platform, ",\\s*")) %>%
  # 2) Unnest, creating one row per platform in the list
  unnest(cols = c(Platform_list)) %>%
  # 3) Rename for clarity
  rename(Platform_single = Platform_list)

#Creating a "clean" data frame exluding all aquitted individuals (although retaining those receiving a sentence but 0 years in prison). 
df_clean <- df_sent %>%
  filter(is.finite(TotalMonths))

```


Significance test of mean difference using Welch ANOVA (not assuming equal variance):
```{r, eval = FALSE}
library(stats)
oneway.test(TotalMonths ~ Platform_single, 
            data = df_clean, 
            var.equal = FALSE)
```


```{r, eval = FALSE}
#Adding a column for mean months in prison per case number and year
df_sent_dev1 <-  df_sent %>%
  mutate(DateY = year(Date)) %>%
  group_by(CaseNumber, DateY) %>%
   mutate(mean_months = mean(TotalMonths, na.rm =T)) %>%
  select(Date, DateY, CaseNumber, TotalMonths, mean_months, Platform, Platform_single, Region) %>%
  ungroup()

# Adding calculated summaries (mean, sd, t-values) for each platform and year
df_sent_dev2 <- df_sent_dev1 %>%
  filter(is.finite(TotalMonths)) %>%
  group_by(DateY, Platform_single) %>%
  summarise(
   # mutate(
    n     = n(),
    mean = mean(TotalMonths),
    sd    = sd(TotalMonths),
    se    = sd / sqrt(n),
     tcrit = qt(0.975, df = pmax(n - 1, 1)),
     lower = mean - tcrit * se,
     upper = mean + tcrit * se,
    .groups = "drop"
           ) 
```

The following code produces figure 3: 

```{r, eval = FALSE}
gg_figure3 <- ggplot(df_sent_dev2, 
       aes(x=DateY, y=mean, color = Platform_single ))+
  geom_point(position = position_dodge(width = 0.3))+
  geom_errorbar(aes(ymin = lower, ymax = upper),
                alpha = 0.4,
                width = 0.5,
                position = position_dodge(width = 0.3))+
  geom_line(position = position_dodge(width = 0.3))+
  theme_minimal()+
  scale_color_manual(values = cbbPalette,
                      name   = "Platform",                       
                     breaks = c("Anom", "EncroChat", "SkyECC"),  
                     labels = c("Anom (n=58)", "EncroChat (n=95)", "SkyECC (n=74)") 
  )+
  xlab("Year")+
  ylab("Mean sentence length in months")+
  theme(legend.position = "bottom")

print(gg_figure3)
```


## Fig. 4: Network analyses

This final section concerns the network analyses in the paper. Here, the interest lays in which crime categories are connected within court cases.

### Wrangling network data

```{r network on crime category PER PLATTFORM, eval =FALSE}
# Create the "splitted" data frame: 
df2 <- df %>%
  # 1) Split the 'Platform' column into a list of platforms
  mutate(Platform_list = str_split(Platform, ",\\s*")) %>%
  # 2) Unnest, creating one row per platform in the list
  unnest(cols = c(Platform_list)) %>%
  # 3) Rename for clarity
  rename(Platform_single = Platform_list)

## ANOM
crimes_longA <- df2 %>% 
  select(!ends_with("_date")) %>%
  filter(Platform_single == "Anom")
## SKY
crimes_longS <- df2 %>% 
  select(!ends_with("_date")) %>%
  filter(Platform_single == "SkyECC")
## ENCRO
crimes_longE <- df2 %>% 
  select(!ends_with("_date")) %>%
  filter(Platform_single == "EncroChat")


## ANOM
#1. Make node attributes tidy
crimes_longA <- crimes_longA %>%
  pivot_longer(cols = Crime1:Crime14,   #starts_with("Crime"),
               values_drop_na = TRUE,
               names_to   = NULL,       # column names are not useful
               values_to  = "Crime")    # each offence in its own row

## SKYECC
crimes_longS <- crimes_longS %>%
  pivot_longer(cols = Crime1:Crime14, 
               values_drop_na = TRUE,
               names_to   = NULL,       
               values_to  = "Crime") 
## ENCRO
crimes_longE <- crimes_longE %>%
  pivot_longer(cols = Crime1:Crime14, 
               values_drop_na = TRUE,
               names_to   = NULL,       
               values_to  = "Crime") 



#Create a "crime category" column, same as above
crimes_longA <-  crimes_longA %>%
  mutate(
    crimcat = case_when(
       Crime %in% Drugs ~ "Drugs",
      Crime %in% Explosives ~ "Explosives",
      Crime %in% Fraud ~ "Fraud",
      Crime %in% Kidnapping_threat ~ "Kidnapping_threat",
      Crime %in% Money_laundering ~ "Money_laundering",
      Crime %in% Other ~ "Other",
      Crime %in% Public_activity ~ "Public_activity",
      Crime %in% Public_danger ~ "Public_danger",
      Crime %in% Theft_robbery ~ "Theft_robbery",
      Crime %in% Traffic ~ "Traffic",
      Crime %in% Trafficking ~ "Trafficking",
      Crime %in% Violence ~ "Violence",
      Crime %in% Weapons ~ "Weapons"
    )
  )

# SKY
crimes_longS <-  crimes_longS %>%
  mutate(
    crimcat = case_when(
       Crime %in% Drugs ~ "Drugs",
      Crime %in% Explosives ~ "Explosives",
      Crime %in% Fraud ~ "Fraud",
      Crime %in% Kidnapping_threat ~ "Kidnapping_threat",
      Crime %in% Money_laundering ~ "Money_laundering",
      Crime %in% Other ~ "Other",
      Crime %in% Public_activity ~ "Public_activity",
      Crime %in% Public_danger ~ "Public_danger",
      Crime %in% Theft_robbery ~ "Theft_robbery",
      Crime %in% Traffic ~ "Traffic",
      Crime %in% Trafficking ~ "Trafficking",
      Crime %in% Violence ~ "Violence",
      Crime %in% Weapons ~ "Weapons"
    )
  )
#ENCRO
crimes_longE <-  crimes_longE %>%
  mutate(
    crimcat = case_when(
       Crime %in% Drugs ~ "Drugs",
      Crime %in% Explosives ~ "Explosives",
      Crime %in% Fraud ~ "Fraud",
      Crime %in% Kidnapping_threat ~ "Kidnapping_threat",
      Crime %in% Money_laundering ~ "Money_laundering",
      Crime %in% Other ~ "Other",
      Crime %in% Public_activity ~ "Public_activity",
      Crime %in% Public_danger ~ "Public_danger",
      Crime %in% Theft_robbery ~ "Theft_robbery",
      Crime %in% Traffic ~ "Traffic",
      Crime %in% Trafficking ~ "Trafficking",
      Crime %in% Violence ~ "Violence",
      Crime %in% Weapons ~ "Weapons"
    )
  )



```

### Build the edge tables

```{r, eval = FALSE}
# Bipartite (person–crime) edges
#ANOM
edges_bipartiteA <- crimes_longA %>% 
  rename(from = SSN, to = crimcat)          # renaming
#SKY
edges_bipartiteS <- crimes_longS %>% 
  rename(from = SSN, to = crimcat)
#ENCRO
edges_bipartiteE <- crimes_longE %>% 
  rename(from = SSN, to = crimcat)

#ANOM
g_bipA <- as_tbl_graph(edges_bipartiteA, directed = FALSE) %>%      # tidygraph object
  mutate(type = name %in% edges_bipartiteA$from)          # TRUE = people, FALSE = crimes
#SKY
g_bipS <- as_tbl_graph(edges_bipartiteS, directed = FALSE) %>%     
  mutate(type = name %in% edges_bipartiteS$from)          
#ENCRO
g_bipE <- as_tbl_graph(edges_bipartiteE, directed = FALSE) %>%     
  mutate(type = name %in% edges_bipartiteE$from)         

# Is now the crime‑crime network.
#ANOM
crime_projA <- g_bipA %>%
  bipartite_projection(which = "false",       
                       multiplicity = TRUE)   
#SKY
crime_projS <- g_bipS %>%
  bipartite_projection(which = "false",       
                       multiplicity = TRUE)   
#ENCRO
crime_projE <- g_bipE %>%
  bipartite_projection(which = "false",       
                       multiplicity = TRUE)   


```

## Networks
Crime categories connected to each other within court cases.


```{r NÄTVERK PÅ CRIMECAT PLATTFORMSVIS, eval = FALSE}
#ANOM
crime_projA <- crime_projA %>% 
 # In case you built it in igraph and only now converted to tidygraph:
  as_tbl_graph() %>%           
  activate(edges) %>% 
  mutate(weight = ifelse(is.na(weight), 1, weight)) %>%  # be sure weight exists
  activate(nodes) %>% 
  mutate(
    degree     = centrality_degree(),       # #linked crime types
  #  strength   = centrality_strength(),     # weighted degree
    community  = as.factor(group_louvain()) # modularity clusters
  )
#SKY
crime_projS <- crime_projS %>% 
  # In case you built it in igraph and only now converted to tidygraph:
  as_tbl_graph() %>%           
  activate(edges) %>% 
  mutate(weight = ifelse(is.na(weight), 1, weight)) %>%  # be sure weight exists
  activate(nodes) %>% 
  mutate(
    degree     = centrality_degree(),       # #linked crime types
  #  strength   = centrality_strength(),     # weighted degree
    community  = as.factor(group_louvain()) # modularity clusters
  )
#ENCRO
crime_projE <- crime_projE %>% 
  # In case you built it in igraph and only now converted to tidygraph:
  as_tbl_graph() %>%           
  activate(edges) %>% 
  mutate(weight = ifelse(is.na(weight), 1, weight)) %>%  # be sure weight exists
  activate(nodes) %>% 
  mutate(
    degree     = centrality_degree(),       # #linked crime types
  #  strength   = centrality_strength(),     # weighted degree
    community  = as.factor(group_louvain()) # modularity clusters
  )

```

Network plot of the above:

```{r network plots, eval = FALSE}

nw_plot_platform <- function(df, title = NULL){
  # Adjust the labels
  lab_map <- c(
    Drugs = "Drugs",
    Trafficking = "Drug trafficking",
    Violence = "Violence",
    Money_laundering = "Money laundering",
    Weapons = "Weapons",
    Public_activity = "Public activity",
    Traffic = "Traffic",
    Fraud = "Fraud",
    Explosives = "Explosives",
    Public_danger = "Public danger",
    Theft_robbery = "Theft/robbery",
    Kidnapping_threat = "Kidnapping/threat"
  )
df2 <- df %>%
    activate(nodes) %>%
    mutate(name_chr = as.character(name),
      label = if_else(name_chr %in% names(lab_map),
                      lab_map[name_chr],name_chr))
  
set.seed(124)  # for reproducible layout

ggraph(df2, layout = "fr") +
  geom_edge_link(aes(width = weight), 
                 colour = "grey70", 
                 alpha  = 0.4) +
  scale_edge_width(range = c(0.2, 3)) + 
  geom_node_point() + #aes(size = strength)) +
  geom_node_text(aes(label = label), repel = TRUE, size = 3) +
  guides(edge_width  = "none",
         size        = "none",
         colour      = guide_legend(title = "Community")) +
  theme_void(base_size = 12)+
  labs(title = title)+
  theme(
      plot.title = element_text(size = 10)
    )
}
```

Plotting the networks:
```{r, eval = FALSE}
anom <- nw_plot_platform(crime_projA, "Anom")
sky <- nw_plot_platform(crime_projS, "SkyECC")
encro <- nw_plot_platform(crime_projE, "EncroChat")
```


