Skip to content

Commit

Permalink
Only retain pending plots method for plot display
Browse files Browse the repository at this point in the history
Drop the older method of autoshow, and document the loss of the ability
to suppress plots with semicolons.
  • Loading branch information
matthew-brett committed Jun 21, 2023
1 parent 14d8467 commit 7232745
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 31 deletions.
32 changes: 18 additions & 14 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# reticulate (development version)

- New optional feature: Reticulate now accepts a new option `jupyter_compat`
set to `FALSE` by default, that changes the default display behavior of
Reticulate chunks, to better match the behavior of Jupyter. In the
Reticulate default, each standalone code expression in the code chunk that
does not end in a semi-colon, generates display of the expression output. For
Matplotlib plots, an explicit `plt.show()` generates the figure, but
otherwise, the chunk (by default) only generates a figure if the last line in
the chunk is an expression returning a recognized Matplotlib object, and
without a semi-colon. With `jupyter_compat=TRUE`, a standalone expression
returning a Matplotlib object, anywhere in the chunk, will cause the plot to
be displayed automatically after the chunk. No expression in the chunk will
set to `FALSE` by default, that changes the default expression output display
behavior of Reticulate chunks, to better match the behavior of Jupyter. In
the Reticulate default, each standalone code expression in the code chunk
that does not end in a semi-colon, generates display of the expression
output. With the `jupyter_compat` option set, no expression in the chunk will
generate output, except if there is a standalone expression as the last code
statement in the chunk, and that expression does not have a semicolon
— a semicolon suppresses the output, as it does for the default behavior.
See [PR](https://github.com/rstudio/reticulate/pull/1394) and [original
issue](https://github.com/rstudio/reticulate/issues/1391).
statement in the chunk, and that expression does not have a semicolon.
A semicolon always suppresses the expression output, for the default and
`jupyter_compat` case. See
[PR](https://github.com/rstudio/reticulate/pull/1394) and [original
issue](https://github.com/rstudio/reticulate/issues/1391) for discussion for
this and the next item.

- Behavior change: Previously, a Matplotlib plot would only be automatically
displayed (without `plt.show()`) if there was a final standalone expression
returning a Matplotlib object, and that expression did not have a final
semicolon. With this update, any standalone expression returning
a Matplotlib object, with or without a semicolon, will cause chunk to display
the plot automatically. See above for discussion.

- Fix: the knitr engine now automatically calls `plt.show()` for matplotlib
bar plots, like it does for other matplotlib plot types (#1391).
Expand Down
22 changes: 5 additions & 17 deletions R/knitr-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ eng_python <- function(options) {

# clear the last value object (so we can tell if it was updated)
py_compile_eval("'__reticulate_placeholder__'")
.engine_context$matplotlib_show_was_called <- FALSE

# run code and capture output
captured <- if (capture_errors)
Expand All @@ -209,8 +208,7 @@ eng_python <- function(options) {
# handle matplotlib and other plot output
captured <- eng_python_autoprint(
captured = captured,
options = options,
autoshow = (last_range & !jupyter_compat)
options = options
)

# In all modes, code statements ending in semicolons always suppress repr
Expand Down Expand Up @@ -457,7 +455,6 @@ eng_python_initialize_matplotlib <- function(options, envir) {
# override show implementation
plt$show <- function(...) {

.engine_context$matplotlib_show_was_called <- TRUE
.engine_context$matplotlib_pending_show = FALSE

# get current chunk options
Expand Down Expand Up @@ -588,7 +585,7 @@ eng_python_altair_chart_id <- function(options, ids) {

}

eng_python_autoprint <- function(captured, options, autoshow) {
eng_python_autoprint <- function(captured, options) {

# bail if no new value was produced by interpreter
value <- py_last_value()
Expand All @@ -607,18 +604,9 @@ eng_python_autoprint <- function(captured, options, autoshow) {

if (eng_python_is_matplotlib_output(value)) {

# by default, we suppress "side-effect" outputs from matplotlib
# objects; only when 'autoshow' is set will we try to render the
# associated matplotlib plot
#
# handle matplotlib output. note that the default hook installed by
# reticulate will update the 'pending_plots' item
if (autoshow && !.engine_context$matplotlib_show_was_called) {
plt <- import("matplotlib.pyplot", convert = TRUE)
plt$show()
} else if (isTRUE(options$jupyter_compat)) {
.engine_context$matplotlib_pending_show <- TRUE
}
# Handle matplotlib output. Note that the default hook for plt.show
# installed by reticulate will update the 'pending_plots' item.
.engine_context$matplotlib_pending_show <- TRUE

# Always suppress Matplotlib reprs
return("")
Expand Down

0 comments on commit 7232745

Please sign in to comment.