Reputation: 447
I am trying to execute a function which plots some data then plays some audio (corresponding to that data) in RStudio. However, it seems that the audio playback blocks the plotting. Why is this?
plot.prod.df <- function(df, row) {
# given a row number and a df, plot the prod df for that trial
# create data
print(paste0("plotting production data. trial: ", row))
if(is.null(df$prod[[row]])){
stop("Invalid trial")
}
else {
# get relevant production data
prod.df <- data.frame("onset" = df$prod[[row]]$onset * 1000,
"pitch" = df$prod[[row]]$pitch,
"error" = df$prod[[row]]$error_boolean)
prod.df$error <- as.factor(prod.df$error)
# get target notes
target.notes <- str.mel.to.vector(df$stimuli.pitch[[row]], "-")
# check if there were playbacktimes
print(df$playback.times[[row]])
if (any(is.na(df$playback.times[[row]]))) {
print("no playback times on this trial")
# plot
ggplot(prod.df, aes(x=onset, y=pitch, color = error)) +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black")) +
geom_hline(yintercept = target.notes, color = magma.colors[4], size = 2, alpha = 0.7) +
geom_point() +
scale_color_manual(values=c(magma.colors[1], magma.colors[2]))
}
else {
playback.times <- fromJSON(df$playback.times[[row]])[2:length(fromJSON(df$playback.times[[row]]))] # remove the default original playback
print(playback.times)
# plot
ggplot(prod.df, aes(x=onset, y=pitch, color = error)) +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black")) +
geom_hline(yintercept = target.notes, color = magma.colors[4], size = 2, alpha = 0.7) +
geom_vline(xintercept = playback.times, color = magma.colors[5], size = 2, alpha = 0.7) +
geom_point() +
scale_color_manual(values=c(magma.colors[1], magma.colors[2]))
}
}
}
# set up WavPlayer
sound::setWavPlayer("./sox/play")
play.seq <- function(midi_notes, length_of_each_note) {
#print("playing sequence user heard")
freqs <- midi_to_freq(midi_notes)
sines <- lapply(freqs, sound::Sine, length_of_each_note)
for (i in seq_along(1:length(sines))) {
Sys.sleep(length_of_each_note)
sound::play(cutSampleEnds(sines[[i]])) # cutSampleEnds removes cracks
}
}
play.and.plot.trial <- function(df, row = NULL) {
# if a row isn't specified, randomly select a row
if (is.null(row)) {
sampled_trial <- sample(1:nrow(df), 1)
}
else {
sampled_trial <- row
}
print(paste0("no. trial to plot: ", sampled_trial))
plot.prod.df(df, sampled_trial)
play.seq(str.mel.to.vector(df$stimuli.pitch[[sampled_trial]], "-"), 0.25)
}
play.and.plot.trial(dat)
I can confirm that if I comment out the following line and run play.and.plot.trial(dat), it plots:
play.seq(str.mel.to.vector(df$stimuli.pitch[[sampled_trial]], "-"), 0.25)
I am not sure why this stops the plotting happening; it only prints to console, I think.
I also tried adding Sys.sleep(5) before the audio playback and this does not help.
Upvotes: 0
Views: 233
Reputation: 160597
print
the grob:
play.and.plot.trial <- function(df, row = NULL) {
# ...
print(plot.prod.df(df, sampled_trial))
play.seq(str.mel.to.vector(df$stimuli.pitch[[sampled_trial]], "-"), 0.25)
}
Calls to ggplot(...) + geom_*(...)
do not actually render into a graphic device. The rendering is done by ggplot2:::print.ggplot
. Try this:
gg <- ggplot(mtcars, aes(mpg, disp)) + geom_path()
Notice how it does not plot to the viewing pane? Now, if you type in gg
on the console, it renders. This is because R will try to figure out the most appropriate way to "print" this type of object. Using S3 method dispatch in R, it uses class(gg)
to look for either print.gg
(not found) or print.ggplot
(found within the ggplot2
package). Since it finds the latter, it uses that.
(If neither were found, it would use print.default
.)
This is also applicable in for
loops, where for instance you want to make multiple plots.
The answer in any event is to explicitly render it. Because of the S3 method dispatch, print(gg)
will still call ggplot2:::print.ggplot
because of how S3 works.
(If you're ever in a situation where you have a gg
object that needs rendering but you have not loaded the ggplot2 namespace with library(ggplot2)
, you can use ggplot2:::print.ggplot(gg)
explicitly. Or you can use it explicitly just because you want your code to be "declarative" and unambiguous, since not knowing how S3 dispatch works might make print(gg)
look magical.)
Upvotes: 1