Execute a Set of Lines from Another R File

Execute a set of lines from another R file

If you're worried about the region of interest will be shifted once you add new lines upstream, then an alternative (or slightly modified) version of MrFlick's answer would be read as:

sourcePartial <- function(fn,startTag='#from here',endTag='#to here') {
lines <- scan(fn, what=character(), sep="\n", quiet=TRUE)
st<-grep(startTag,lines)
en<-grep(endTag,lines)
tc <- textConnection(lines[(st+1):(en-1)])
source(tc)
close(tc)
}

Now you need to put a small, unique hash tag just above and below of the region of interest. Such as "#from here" and "#to here"

Source only part of a file

Using the right tool for the job …

As discussed in the comments, the real solution is to use an IDE that allows sourcing specific parts of a file. There are many existing solutions:

  • For Vim, there’s Nvim-R.

  • For Emacs, there’s ESS.

  • And of course there’s the excellent stand-alone RStudio IDE.

As a special point of note, all of the above solutions work both locally and on a server (accessed via an SSH connection, say). R can even be run on an HPC cluster — it can still communicate with the IDEs if set up properly.

… or … not.

If, for whatever reason, none of the solutions above work, here’s a small module[gist] that can do the job. I generally don’t recommend using it, though.1

#' (Re-)source parts of a file
#'
#' \code{rs} loads, parses and executes parts of a file as if entered into the R
#' console directly (but without implicit echoing).
#'
#' @param filename character string of the filename to read from. If missing,
#' use the last-read filename.
#' @param from first line to parse.
#' @param to last line to parse.
#' @return the value of the last evaluated expression in the source file.
#'
#' @details If both \code{from} and \code{to} are missing, the default is to
#' read the whole file.
rs = local({
last_file = NULL

function (filename, from, to = if (missing(from)) -1 else from) {
if (missing(filename)) filename = last_file

stopifnot(! is.null(filename))
stopifnot(is.character(filename))

force(to)
if (missing(from)) from = 1

source_lines = scan(filename, what = character(), sep = '\n',
skip = from - 1, n = to - from + 1,
encoding = 'UTF-8', quiet = TRUE)
result = withVisible(eval.parent(parse(text = source_lines)))

last_file <<- filename # Only save filename once successfully sourced.
if (result$visible) result$value else invisible(result$value)
}
})

Usage example:

# Source the whole file:
rs('some_file.r')
# Re-soure everything (same file):
rs()
# Re-source just the fifth line:
rs(from = 5)
# Re-source lines 5–10
rs(from = 5, to = 10)
# Re-source everything up until line 7:
rs(to = 7)

1 Funny story: I recently found myself on a cluster with a messed-up configuration that made it impossible to install the required software, but desperately needing to debug an R workflow due to a looming deadline. I literally had no choice but to copy and paste lines of R code into the console manually. This is a situation in which the above might come in handy. And yes, that actually happened.

How can I run multiple lines of code in R

Click on header Tools, then Global Options..., then Code, then Ctrl + Enter Executes and choose Multi-line R statement

Define all functions in one .R file, call them from another .R file. How, if possible?

You can call source("abc.R") followed by source("xyz.R") (assuming that both these files are in your current working directory.

If abc.R is:

fooABC <- function(x) {
k <- x+1
return(k)
}

and xyz.R is:

fooXYZ <- function(x) {
k <- fooABC(x)+1
return(k)
}

then this will work:

> source("abc.R")
> source("xyz.R")
> fooXYZ(3)
[1] 5
>

Even if there are cyclical dependencies, this will work.

E.g. If abc.R is this:

fooABC <- function(x) {
k <- barXYZ(x)+1
return(k)
}

barABC <- function(x){
k <- x+30
return(k)
}

and xyz.R is this:

fooXYZ <- function(x) {
k <- fooABC(x)+1
return(k)
}

barXYZ <- function(x){
k <- barABC(x)+20
return(k)
}

then,

> source("abc.R")
> source("xyz.R")
> fooXYZ(3)
[1] 55
>

Execute R files through an R script

You can use the source command and pass it the filename. try ?source

Run a R script for all files in a directory, and store the outputs in one common data frame

Unfortunately, the answer provided by Álvaro does not work as expected, since the output repeats the same number with different organisation names, making it really difficult to read. Actually, the number 20 is repeated 20 times, the number 11, 11 times, and so on. The information is there, but it is not accessible without further data treatment.

I was doing my own research in the meantime and I got to the following code. Finally I made it to work, but the data format was "matrix" "array", really confusing. Fortunately, I wrote the last lines to transpose the data, unlist the array and convert in a matrix, which is able to be converted in a data frame and manipulated as usual.

Maybe my explanation is not very useful, and since I am a newbie, I am sure the code is far from being elegant and optimised. Anyway, please review the code below:

library(purrr)
library(rjson)
library(dplyr)
library(tidyverse)
setwd("~/documentos/varios/proyectos/programacion/R/psa_twitter")

# Load data from files.
archivos <- list.files("./raw_data/json_files",
pattern = ".json",
full.names = TRUE)
psa_handles <- read_csv(file = "./raw_data/psa_handles.csv") %>%
select(Name, AKA, Twitter)

nr_archivos <- length(archivos)

calcula_cuentas <- function(a){
# Extract lists
json_data <- fromJSON(file = a)
org_aka <- json_data$id
org_meta <- json_data$metadata
org_name <- org_meta$company

twitter <- json_data$twitter
following <- twitter$following
# create an empty vector to populate
longitud = length(following)
names <- vector(length = longitud)

# loop to populate the empty vector with third element of the sub-list
for(i in 1:longitud){
names[i] <- following[[i]][3]
}
# create a data frame and change column name
names_list <- data.frame(sapply(names, c))
colnames(names_list) <- "usernames"

# Create a data frame with the correct formatting ready to comparison
org_handles <- data.frame(paste("@",
names_list$usernames,
sep="")
)
colnames(org_handles) <- "Twitter"

# merge tables
org_list <- inner_join(psa_handles, org_handles)
cuentas_db_org <- length(org_list$Twitter)
cuentas_total_org <- length(twitter$following)
results <- data.frame(Name = org_name,
AKA = org_aka,
Cuentas_db = cuentas_db_org,
Total = cuentas_total_org)
results
}

# apply function to list of files and unlist the result
psa <- sapply(archivos, calcula_cuentas)
psa1 <- t(as.data.frame(psa))
psa2 <- matrix(unlist(psa1), ncol = 4) %>%
as.data.frame()
colnames(psa2) <- c("Name", "AKA", "tw_int_outbound", "tw_ext_outbound")

# Save the results.
saveRDS(psa2, file = "rda/psa.RDS")


Related Topics



Leave a reply



Submit