Rogue
Rogue

Reputation: 29

How to use paste in for loop in R? to change exif data of photos

I am working on a MacOS Big Sur 11.6 with R version 4.0.4 (2021-02-15)

I am trying to use paste() within a for loop but I need the values within the paste function to change with each iteration.

I have a data frame like this:

            pathname S
1 user/folder/photo1 A
2 user/folder/photo2 B
3 user/folder/photo3 C

and I am trying to add an EXIF Comment tag to the metadata of my photos. I would like the Comment tag to change based on the S column value. I have code like this:

for(i in df$pathname){
  x <- df$S[i]
  sysCommand <- paste("exiftool -Comment=x i")
  system(sysCommand)
}

The inputs (i.e. x and i) within the paste function should change as it goes through the list.

Thank you for your help!

Upvotes: 1

Views: 360

Answers (2)

Dave2e
Dave2e

Reputation: 24139

To expand upon @Greg's excellent explanation of the paste function. There are a couple of flaws in the logic related to accessing the data in the data frame.

Also is paste() is a vectorized function, it is easier to make a vector of the system commands and then just use the loop just to execute the commands. This avoids with dealing with the subscripts.

data<- read.table(header=TRUE, text="          pathname S
user/folder/photo1 A
user/folder/photo2 B
user/folder/photo3 C")


#paste is vectorized function
# create a list of all of the requested system commands
commands <-paste0("exiftool -Comment=", data$S, " ", data$pathname) 

#loop through the vectors of command
for (i in commands) {
   print(i)  #debugging
  system(i)  
}

Upvotes: 2

Greg
Greg

Reputation: 3326

Where You Went Wrong

Your interpretation of paste() is flawed. This function takes R objects and concatenates their string representations.

So given

name <- "Rogue"

then the code

paste("Hi name!", "  How are you?")

will simply concatenate the string objects "Hi name!" and " How are you?" to yield

[1] "Hi name!  How are you?"

To substitute in the name, one must use the name object

paste("Hi ", name, "!", "  How are you?")
#            ^^^^

to obtain

[1] "Hi Rogue!  How are you?"

Solution 1: Use paste() Correctly

As the comments rightly suggest, the proper use of paste() would be

  # ...

  sysCommand <- paste("exiftool -Comment=", x, " ", i, sep = "")
  #                                                    ^^^^^^^^
  #                                                    Avoid unwanted spaces.

  # ...

with care to include the argument sep = "", and thus avoid extra spaces like those in "exiftool -Comment= A 1". Each result should look like this:

[1] "exiftool -Comment=A 1"

Note

The paste0() function omits extra spaces automatically, so it has no need for sep = "".

Solution 2: The glue Package

To make things work the way you expected, you could use the glue package.

  # ...

  sysCommand <- glue::glue("exiftool -Comment={x} {i}")

  # ...

with care to "embrace" every variable name with { }. Each result should look like

exiftool -Comment=A 1

a glue object that is also a normal string.

Note

As I mention in my comment

You've extracted your data incorrectly with for(i in df$pathname) and df$S[i]. When you use i in df$pathname, you're iterating with i over the strings "user/folder/photo1", "user/folder/photo2", and so forth. By contrast, df$S[i] expects a number within the [ ], as it attempts to take the value in the ith place of column S. Since it can't interpret a string like "user/folder/photo1" as a numeric index, the operation df$S[i] returns an NA value...which paste() interprets as the string "NA".

your original code also erred logically when accessing the data in df. The nifty answer by @dave2e offers a cleanly vectorized solution to this error.

That said, your correction does well in fixing this issue

for(i in 1:length(df$pathname)){
  #for each photo
  x <- df$S[i]
  pathname <- df$pathname[i]

  syscommand <- paste("exiftool -Comment=", site, " ", pathname, sep = "")   
  system(syscommand)
} 

and it retains the structure of your original loop. I'm happy to hear it works!

Upvotes: 3

Related Questions