如何解决R Shiny中plot.new报错:figure margins too large的问题?
我明白你遇到的麻烦了——用Shiny做的绘图下载功能,选高分辨率时就弹出“figure margins too large”错误,还得重启应用,确实闹心。既然你用的是base R绘图,不用ggplot2的ggsave,咱们可以从两个方向解决这个问题,都是不用重启应用的简便方法:
方法一:调整绘图边距,强制适配小尺寸区域
这个错误本质是当你把分辨率调得很高,但固定了绘图的像素宽高时,实际的绘图物理尺寸(英寸)会变得很小,默认的边距(用来放轴标签、标题的空间)占比太大,超出了绘图区域。咱们可以手动设置更小的边距来解决:
修改你的downloadHandler里的内容,在调用plot()之前加上par(mar = c(3, 3, 1, 1)),手动缩小边距:
output$download_plot <- downloadHandler( filename = function() { paste("plot", ".png", sep = "") }, content = function(file) { png(file, width = 800, height = 600, res = input$res) # 设置更小的边距:下、左、上、右的边距(单位:行) par(mar = c(3, 3, 1, 1)) plot(mtcars$wt, mtcars$mpg, xlab = "Weight", ylab = "Miles per gallon") dev.off() } )
解释一下:par(mar)的四个值分别对应底部、左侧、顶部、右侧的边距,默认是c(5,4,4,2)+0.1,咱们把它调小后,即使绘图区域物理尺寸很小,也能放下必要的标签,不会触发边距过大的错误。你可以根据自己的需求微调这四个数值,比如如果标签还是显示不全,就稍微调大一点对应方向的边距。
方法二:固定物理尺寸,让像素数随分辨率变化
如果你希望保持绘图的物理大小(比如8英寸宽、6英寸高),同时让分辨率变化时自动调整像素数,那就把png()里的width和height改成英寸单位,再搭配res参数:
output$download_plot <- downloadHandler( filename = function() { paste("plot", ".png", sep = "") }, content = function(file) { # width和height用英寸,res是每英寸点数,像素数=width*res png(file, width = 8, height = 6, units = "in", res = input$res) plot(mtcars$wt, mtcars$mpg, xlab = "Weight", ylab = "Miles per gallon") dev.off() } )
这样一来,不管你选多少分辨率,绘图的物理尺寸都是固定的,边距占比正常,就不会出现边距过大的问题。而且分辨率越高,生成的图片像素数越多,细节也更清晰,这也是更符合“分辨率调整”预期的做法。
这两种方法都不需要重启Shiny应用,选高分辨率时直接就能正常下载。你可以根据自己的需求选一种,比如如果想要固定像素大小就用方法一,想要固定打印尺寸就用方法二。
备注:内容来源于stack exchange,提问作者Wang

