Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move all plot watching logic into watchout #151

Merged
merged 11 commits into from
Jun 19, 2024
Merged

Move all plot watching logic into watchout #151

merged 11 commits into from
Jun 19, 2024

Conversation

hadley
Copy link
Member

@hadley hadley commented Jun 19, 2024

This eliminates a bunch of fiddly state management, and centralises the concern of figuring out if a plot should be recorded into one place.

@hadley hadley requested a review from cderv June 19, 2024 07:49
plot <- plot && identical(dev, dev.cur())
out <- watcher(plot, incomplete_plots)
output <<- c(output, out)
out <- list(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this interface so it's likely to change in a future PR.

R/watcher.R Outdated
if (!identical(dev.cur(), dev)) {
return()
}
# cur_devs <- dev.list()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cderv I left this code in but commented out to deliberately draw your attention to it. I'm pretty sure the logic is redundant (because if the device list has changed then that implies the current device has changed) and it doesn't cause any tests to fail. I think it was included because the logic was previously split over two functions and so it was harder to see that it was redundant. But it is a change and I wanted to double check that I didn't miss anything.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this seems redundant.

It seems all this have been introduced over time to fix different bugs. Some have tests that are passing, and other may not have test.

I am seeing that dev <- dev.cur() was previously called evaluate_top_level_expression() so for each parsed expression

evaluate/R/eval.R

Lines 157 to 163 in e8bd6f5

dev <- dev.cur()
handle_output <- function(plot = TRUE, incomplete_plots = FALSE) {
# if dev.cur() has changed, we should not record plots any more
plot <- plot && identical(dev, dev.cur())
out <- watcher(plot, incomplete_plots)
output <<- c(output, out)
}

Now we call it once when creating watcher with watchout() call, and the check in capture_plot() based on initial value.

I tried to see if this could cause problems, but it seems not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm reasonably certain that I got that logic right, and I added a few more tests to capture various situations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW in general if you're trying to find problems it's useful to consider the distinction between evaluate("plot(1); lines(2)") and evaluate("plot(1)\nlines(2)")

Copy link
Collaborator

@cderv cderv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Toook me some time too look at this, and think if this could cause issue. I ran tests also from knitr and knitr-example. It seems all good.

I noticed some possible change in order we are doing things, but it seems to work ok.

@@ -117,6 +95,7 @@ evaluate <- function(input,
output_handler = output_handler,
include_timing = include_timing
)
watcher$check_devices()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious: what does motivate the move for this refactored code after evaluate_top_level_expression ?

All tests are passing so seems good - but wanted to understand the thinking as I would have place it in the same place by precaution

Copy link
Member Author

@hadley hadley Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over time, my plan is to move to more and more logic in to evaluate() so the logic is more clear. In this case specifically, I think it makes sense to check the devices after you've run the user code, rather than before. (Although the net effect is generally going to be the same.)

R/watcher.R Outdated
if (!identical(dev.cur(), dev)) {
return()
}
# cur_devs <- dev.list()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this seems redundant.

It seems all this have been introduced over time to fix different bugs. Some have tests that are passing, and other may not have test.

I am seeing that dev <- dev.cur() was previously called evaluate_top_level_expression() so for each parsed expression

evaluate/R/eval.R

Lines 157 to 163 in e8bd6f5

dev <- dev.cur()
handle_output <- function(plot = TRUE, incomplete_plots = FALSE) {
# if dev.cur() has changed, we should not record plots any more
plot <- plot && identical(dev, dev.cur())
out <- watcher(plot, incomplete_plots)
output <<- c(output, out)
}

Now we call it once when creating watcher with watchout() call, and the check in capture_plot() based on initial value.

I tried to see if this could cause problems, but it seems not.

@hadley hadley merged commit fe54e17 into main Jun 19, 2024
13 checks passed
@hadley hadley deleted the watch-plot branch June 19, 2024 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants