knitr中Python代码块图形尺寸无法动态修改的问题求助
解决knitr中Python代码块图形尺寸无法修改的问题
问题现象
在包含R和Python代码块的knitr文档(如Rmd)中,若在第一个Python代码块前通过knitr::opts_chunk$set(fig.width = ..., fig.height = ...)设置全局图形尺寸,后续所有Python绘图都会固定使用这个初始尺寸——无论是再次调用knitr::opts_chunk$set()修改全局设置,还是为单个Python代码块指定fig.width/fig.height参数,都无法生效。
复现代码(py.Rmd)
--- title: 'Figure options for Python with knitr' output: html_document ---
```{r opts} knitr::opts_chunk$set(fig.width = 6, fig.height = 5)
```python ```{python setup} import pandas as pd from matplotlib import pyplot as plt d = pd.DataFrame({"x": [1, 2, 3, 4, 5], "y": [1, 3, 2, 5, 4]})
```r ```{r opts2} knitr::opts_chunk$set(fig.width = 2, fig.height = 6)
```python ```{python line, fig.width = 2, fig.height = 6} d.plot.line(x = 'x', y = 'y') plt.show()
```python ```{python bar, fig.width = 6, fig.height = 2} d.plot.bar(x = 'x', y = 'y') plt.show()
执行`rmarkdown::render("py.Rmd")`后,两个Python绘图均为6×5尺寸,而非指定的自定义尺寸。 ## 原因分析 这是因为reticulate在初始化Python环境时,会将第一次从knitr获取的图形尺寸写入matplotlib的全局`rcParams`配置中。之后knitr的参数变更无法自动同步到matplotlib的运行时配置,单个代码块的参数也不会主动覆盖已初始化的matplotlib设置。 ## 解决方案 ### 方法1:直接在Python中控制图形尺寸(推荐) 绕过knitr的参数,直接在Python代码里设置matplotlib的图形尺寸,灵活度更高: #### 方式1:修改全局默认配置 在Python初始化代码块中设置全局默认尺寸,后续需要修改时,在对应代码块中重新覆盖: ```python ```{python setup} import pandas as pd from matplotlib import pyplot as plt # 初始全局默认尺寸 plt.rcParams['figure.figsize'] = [6, 5] d = pd.DataFrame({"x": [1, 2, 3, 4, 5], "y": [1, 3, 2, 5, 4]})
```python ```{python line} # 临时修改当前代码块的全局尺寸 plt.rcParams['figure.figsize'] = [2, 6] d.plot.line(x = 'x', y = 'y') plt.show()
```python ```{python bar} # 再次修改尺寸 plt.rcParams['figure.figsize'] = [6, 2] d.plot.bar(x = 'x', y = 'y') plt.show()
#### 方式2:为单个图形单独设置尺寸 如果只需要调整某一张图的尺寸,直接在绘图前用`plt.figure()`指定: ```python ```{python line} # 仅当前图形使用该尺寸 plt.figure(figsize=(2, 6)) d.plot.line(x = 'x', y = 'y') plt.show()
### 方法2:通过knitr钩子同步参数到matplotlib 如果习惯用knitr的参数体系,可以自定义一个knitr钩子,在每个Python代码块执行前,将当前代码块的图形尺寸参数同步到matplotlib: ```r ```{r hook-setup} # 定义空值替换函数(若未安装rlang包) `%||%` <- function(a, b) if (is.null(a)) b else a knitr::knit_hooks$set(python = function(before, options, envir) { if (before) { # 获取当前代码块的图形尺寸(优先用代码块参数,其次全局设置) fig_w <- options$fig.width %||% knitr::opts_chunk$get("fig.width") fig_h <- options$fig.height %||% knitr::opts_chunk$get("fig.height") # 将尺寸传递给matplotlib reticulate::py_run_string(sprintf( "import matplotlib.pyplot as plt; plt.rcParams['figure.figsize'] = [%s, %s]", fig_w, fig_h )) } })
添加这个钩子后,后续无论是修改全局`knitr::opts_chunk$set()`的参数,还是为单个Python代码块指定`fig.width`/`fig.height`,都会自动同步到matplotlib的配置中,生效对应尺寸。 内容的提问来源于stack exchange,提问作者Achim Zeileis
相关产品推荐
相关产品推荐

