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

Sizing of *saved* figures #2266

Open
tfjaeger opened this issue Jul 1, 2023 · 2 comments
Open

Sizing of *saved* figures #2266

tfjaeger opened this issue Jul 1, 2023 · 2 comments

Comments

@tfjaeger
Copy link

tfjaeger commented Jul 1, 2023

This is more of a feature request / curious question (after a lot googling and reading). I've noticed that fig.width, fig.height, etc. do not seem to determine the size of figures in the files that are saved as part of knitting (in fig.path), even when taking into account dpi.

For example, for a figure for which fig.width = 10 and fig.height = 10.5 (and default 72 dpi), I'm getting a 2580 × 1440 PNG figure (at 72 dpi) from knitting. But that is a width of 35.83 in instead of 10. My colleagues and I (all working on different MacOS versions, with fully up-to-date R, RStudio, and knitr versions) all experience this issue. Indeed, I can't remember this ever not having been the case. Is there a reason, why fig.width and fig.height would not directly spell out into the dimension of the figure, like in a ggsave command?

(For context, for final journal submissions/proofs, we usually need to submit all figures separately from the knitted document. This tends to result in a hotchpotch of figure sizes in the journal proofs, undoing all of our careful work to keep panel sizes, text sizes, etc. identical across figures. We'd love to be able to tell publisher to simply print all figures at 100% of their size but that's only possible if those sizes make sense.)

Sorry, if this is a stupid question that has been answered before. But we have been unable to find any solution to this issue (short of generating all figures both through knitr and ggsave), and since it's an issue that is affecting all of our projects, I'd thought I ask for your wisdom =). Thank you for your time, and any pointer you might be able to provide!

               _                           
platform       aarch64-apple-darwin20      
arch           aarch64                     
os             darwin20                    
system         aarch64, darwin20           
status                                     
major          4                           
minor          3.0                         
year           2023                        
month          04                          
day            21                          
svn rev        84292                       
language       R                           
version.string R version 4.3.0 (2023-04-21)
nickname       Already Tomorrow            
@cderv
Copy link
Collaborator

cderv commented Jul 3, 2023

Thanks for the report.

First let's not there is fig.width and fig.height, dpi but also fig.retina or fig.asp which are taken into account. The output size in document will also be out.width and out.height

  • if fig.asp is specific fig.height will be calculated from fig.width

    knitr/R/utils.R

    Lines 278 to 287 in 0b6bee2

    # handle aspect ratio/figure dimensions; give priority to fig.dim, with
    # warning (seems relatively more likely as user's intention in case when both
    # present) if aspect ratio is specified, calculate figure height
    fix_asp = is.numeric(options$fig.asp)
    if (length(options$fig.dim) == 2L) {
    if (fix_asp) warning('The chunk option fig.asp is ignored since fig.dim is provided.')
    options$fig.width = options$fig.dim[1L]; options$fig.height = options$fig.dim[2L]
    } else {
    if (fix_asp) options$fig.height = options$fig.width * options$fig.asp
    }

  • if out.width or out.height is not specified, the output size in pixel will be calculated from fig.* x dpi.

    knitr/R/utils.R

    Lines 289 to 295 in 0b6bee2

    # out.[width|height].px: unit in pixels for sizes
    for (i in c('width', 'height')) {
    options[[sprintf('out.%s.px', i)]] = options[[o <- sprintf('out.%s', i)]] %n%
    (options[[sprintf('fig.%s', i)]] * options$dpi)
    # turn x% to x/100\linewidth or \textheight
    if (is_latex_output()) options[o] = list(latex_percent_size(options[[o]], i))
    }

  • If fig.retina is set to different than 1, then if out.width not set then it will be computed from fig.width * dpi. And dpi will be transformed to dpi * fig.retina

So it is already quite complex to follow. There is also a specific configuration where if out.width is not set, the value is computed from DPI :

knitr/R/output.R

Lines 608 to 609 in 0b6bee2

if (is.null(options[['out.width']]))
options['out.width'] = list(raster_dpi_width(x[i], dpi))

Is there a reason, why fig.width and fig.height would not directly spell out into the dimension of the figure, like in a ggsave command?

Regarding plot saving, the chunk device is opened consideing the fig.width and fig.height but also DPI which could be modified by fig.retina

knitr/R/block.R

Lines 372 to 377 in 0b6bee2

chunk_device = function(options, record = TRUE, tmp = tempfile()) {
width = options$fig.width[1L]
height = options$fig.height[1L]
dev = fallback_dev(options$dev)
dev.args = options$dev.args
dpi = options$dpi

Can you try setting fig.retina = 1 as options in your document to see if that behave more as your are expecting ?

Hope this helps understand a bit more the internals

@tfjaeger
Copy link
Author

tfjaeger commented Jul 5, 2023

Thank you so much for the detailed response. We will try the retina option (I was aware of the other options and am pretty sure that they don't explain what we see, but we had not explicitly specified retina). I'll update this post once I'll have more to report.

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

No branches or pull requests

2 participants