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

Time:10-26

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!

CodePudding user response:

To expand upon @Greg's excellent answer of paste function. You have a couple of flaws in your logic concerning 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 saves 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)  
}

CodePudding user response:

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!

  • Related