quarto-dev / quarto-r

R interface to quarto-cli
https://quarto-dev.github.io/quarto-r/
144 stars 22 forks source link

Can't specify output directory with `quarto_render()` #81

Open lawalter opened 1 year ago

lawalter commented 1 year ago

There is no parameter for quarto_render() that allows the user to set a desired output directory when rendering a .qmd document.

In rmarkdown::render() this functionality is seen with the output_dir parameter.

The use case I have for setting an output directory, other than it being generally useful, is rendering a .qmd template from an R package. Currently, quarto_render() attempts to write the output document to the location of the template in the R package directory. This therefore limits the utility of quarto templates in R packages. I would like to see quarto_render() to work as rmarkdown::render() does, which allows users to set an output directory for the destination of a rendered template.

cderv commented 1 year ago

Quarto is a CLI tool and quarto_render() is a wrapper on quarto render call. This means that all options supported by the R packages would be ones supported by quarto itself.

For project Quarto has a output-dir option (e.g for books: https://quarto.org/docs/books/book-output.html#output-path) which allows to pass a folder relative to project directory. This argument is missing in R function even if exist in the CLI. We could add it.

However, it seems here you are in another use case.

The use case I have for setting an output directory, other than it being generally useful, is rendering a .qmd template from an R package

How are you rendering the template qmd ? Usually with templates, they should be moved to a project location. This is how it works with R Markdown templates (using the rmarkdown::draft() function). How are you storing and distributing the template in your R Package ? Are you leveraging rmarkdown::draft() or another copy to setup function ?

Moving template file and resources before rendering is important because rendering could need to write some files at the source location. Having an output directory to move results may not be enough.

Is the pattern :

Let's discuss this further.

Hope it helps.

lawalter commented 1 year ago

Hi @cderv,

I'm in the second situation, in terms of the template is a parameterized report.

I render the .Rmd template from the inst directory within the R package. A function in the R package leverages rmarkdown::render() by calling the .Rmd template using system.file("templates", "template.Rmd", package = "Rpackagename") and taking specified params for data directories, an output directory, and an output file name. Users can therefore set any local path and any desired file name and rmarkdown::render uses them via its output_dir and output_file params.

When I tried this using quarto::quarto_render(), I realized there were no similar output options and the template was attempted to be written to the R package directory itself.

cderv commented 1 year ago

Thanks for the precision. I know the situation. This is my personal view on this

I would not try to call render on the file within the package. You will consider folder system.file("templates", "template.Rmd", package = "Rpackagename") as being writeable for work need. But really it means that anytime the user is rendering, some content could be written inside the package installation folder. output_dir and output_file, does not mean that rendering will happen elsewhere. It is possible the intermediates file and other are written to the installation folder.

I would say this is not good practice, all the more because in some situation, a package installation folder is not writeable and will be read -only.

For this type of need, I would use the following pattern.

This will be safer for your rendering, and it is good practice for a package to only write in specific place (temporary directory or user's data directory for things that should stay).

With that in mind, you may understand better the Quarto approach.

Managing outputs for users was very tricky and prone to error. Between the inputs, the resources, the intermediary outputs, the different formats and all. We had a hard time in rmarkdown and it is buggy in some place. (lots of opened issues https://github.com/rstudio/rmarkdown/issues?q=label%3A%22theme%3A+paths%22+is%3Aopen+sort%3Aupdated-desc)

So for now, Quarto does things minimal on this. It may evolve in the future, but I believe the good practice will stay.

Hope it helps understand.

Would you be willing to try one of the approach above ?

lawalter commented 1 year ago

But really it means that anytime the user is rendering, some content could be written inside the package installation folder. output_dir and output_file, does not mean that rendering will happen elsewhere. It is possible the intermediates file and other are written to the installation folder.

Since parameters supplied to rmarkdown::render() params output_dir and output_file are required by the R function, it is impossible that the .Rmd would ever be written to the R directory when using the workflow I have created (with the template inside the R package).

I am aware of workarounds, such as bypassing quarto::quarto_render() entirely by copying the template to a local directory (e.g. Spencer Schien's blog post) and then rendering, but this is an exhausting workaround compared to rmarkdown::render(). I will list several reasons:

1) I create periodic parameterized reports and write them to a shared drive for coworkers to read. Using a template that is stored within the R package is simple and easy. I do not want to copy a template to a local drive or keep a template in a shared directory. 2) Any time I create a .qmd document, not just through an R package template, I have no way to write the rendered output to a desired directory. Working code and rendered documents are often stored separately in organized, professional environments. It wastes time and energy to have to complete a separate step to copy and/or cut and paste the rendered .html or .pdf Quarto document every single time one is created. 3) Quarto has been heralded as the Rmarkdown replacement, but without the ability to render a .qmd to a desired location, I see quarto::quarto_render() as substantially inferior to .Rmd and rmarkdown::render().

cderv commented 1 year ago

Since parameters supplied to rmarkdown::render() params output_dir and output_file are required by the R function, it is impossible that the .Rmd would ever be written to the R directory when using the workflow I have created (with the template inside the R package).

I was thinking of intermediates file mainly. I recall that in some case the output_dir had effect only at the end for the results, and that during the rendering the intermediates files and resources could be written locally to the Rmd file during knitting and pandoc conversion before being moved in the output destination. Paths are really tricky to handle and base expectation is that everything happens at Rmd level at first. Those options are here to tweak that but I think I have seen report of leftover during the processing. Usually clean up - but anyhow, that is my warning. Maybe with your formats it works ok (it could have been for PDF only - I need to look in opened issues).

  1. I create periodic parameterized reports and write them to a shared drive for coworkers to read. Using a template that is stored within the R package is simple and easy. I do not want to copy a template to a local drive or keep a template in a shared directory.

I don't recommend too. I am advising to copy resources from your package to a temp directory for the rendering process and then move stuff to end destination, before cleaning stuff. That is the process recommended in Shiny apps for example (https://shiny.rstudio.com/articles/generating-reports.html)

  1. Any time I create a .qmd document, not just through an R package template, I have no way to write the rendered output to a desired directory. Working code and rendered documents are often stored separately in organized, professional environments.

Here you are referring to using quarto render directly and not with the R package ? In quarto the extension mechanism is what allows to share formats and templates between project and users. https://quarto.org/docs/extensions/ R package only works for R users regarding distribution and are limite to template file where Extensions offers much more customisation.

Regarding output directory for a rendering, you should add to this discussion and follow https://github.com/quarto-dev/quarto-cli/discussions/2171

It wastes time and energy to have to complete a separate step to copy and/or cut and paste the rendered .html or .pdf Quarto document every single time one is created.

Sorry I may have misunderstood then. I though you were offering a function in package as wrapper of quarto_render() that would do those step for users. Like myorg::custom_render(...) that your user would call.

  1. Quarto has been heralded as the Rmarkdown replacement,

Quarto is an evolution of R Markdown for next generation scientific publishing. It does not replace R Markdown in the way that R Markdown is not going away, and Quarto even use part of R Markdown internally. Quarto extends R Markdown ecosystem that R users benefits since some years to other scientific communities by starting fresh with the experience and new vision.

but without the ability to render a .qmd to a desired location, I see quarto::quarto_render() as substantially inferior to .Rmd and rmarkdown::render().

Something I may have missed and misunderstood: Do you manage to do what you want with Quarto CLI calling quarto render in terminal and something is missing in quarto R 📦

Quarto works with the notion of projects which brings many new features and possibility, and offer the mechanism of extensions to offer shared content.

Maybe the current design of Quarto does not yet answer to your past workflow, or maybe this workflow needs adaptation. Anyway, I don't think this is a direct issue of the R package Quarto which this issue thread is about. You should contribute to linked discussion or open a new one to share your feedback. I'll do internally.

I was trying to help find a good workflow to work with quarto and templates. I am happy to keep sharing and help on that if you think that is useful to you.

Anyway, thanks a lot for the discussion by the way. That is very enlightening. I wonder what we could do at the R package level. But we want to keep it as close to Quarto itself.

lawalter commented 1 year ago

I was thinking of intermediates file mainly. I recall that in some case the output_dir had effect only at the end for the results, and that during the rendering the intermediates files and resources could be written locally to the Rmd file during knitting and pandoc conversion before being moved in the output destination.

While rendering with rmarkdown, the intermediates file appears at the output_dir.

Anyway, I don't think this is a direct issue of the R package Quarto which this issue thread is about. You should contribute to linked discussion or open a new one to share your feedback. I'll do internally.

I view this as a quarto R package issue. I typically render .qmd documents outside of a project structure. Maybe Quarto documents were not intended to be rendered that way. However, it seems strange that the output directory cannot be specified with quarto_render(). I like to pass along R code to others for full reproducibility, using quarto render on the command line limits that. I prefer the rmarkdown::render() structure that can pinpoint, specifically, where a document is rendered to. The constraint of only rendering a .qmd in the same directory creates several limitations which were noted by others in the discussion you linked, namely this one: https://github.com/quarto-dev/quarto-cli/discussions/2171#discussioncomment-4291251.

Thanks for the discussion as well, I do look forward to seeing Quarto and the R package quarto evolve over time.

cderv commented 1 year ago

I view this as a quarto R package issue. I typically render .qmd documents outside of a project structure

Oh that is interesting. So this is really something in the usage context of R template within package... 🤔

However, it seems strange that the output directory cannot be specified with quarto_render()

We are currently only passing argument to quarto render and the function is a wrapper. We don't do any logic on the rendering. So doing this in the R package only without making quarto render works differently seems a bit more than a wrapper to CLI tool.

There is a quarto inspect endpoint, exposed as quarto_inspect() that gives all the infos to help integrating quarto in other workflows (package targets uses that for example). There should be information on resources and output in there.

Anyway, the upstream issue is about all this, so this will evolves in time.

Thank you again.

salim-b commented 11 months ago

I'd love quarto_render() to have an output_dir parameter, too.

Currently, quarto_render() attempts to write the output document to the location of the template in the R package directory.

Actually, quarto_render() just writes to the current working directory, so a simple workaround involves first switching into the desired output folder before rendering. Something like:

setwd("to/wherever_output_should_be_written_to/")
quarto::quarto_render(input = "../../inst/my.qmd",
                      output_format = "html")
setwd("../..")

or

withr::with_dir(
  new = "to/wherever_output_should_be_written_to/",
  code = quarto::quarto_render(input = "../../inst/my.qmd",
                               output_format = "html")
)

Update: I was wrong about the above. Please ignore.

lawalter commented 11 months ago

Actually, quarto_render() just writes to the current working directory, so a simple workaround involves first switching into the desired output folder before rendering.

@salim-b I just tested changed the working directory to the desired output directory using setwd() before running quarto_render(). It did not work. The output .html rendered where the template is located in the local R directory, not in the output directory I specified. This failed both inside and outside of a function.

salim-b commented 11 months ago

This failed both inside and outside of a function.

You're absolutely right. I got confused, sorry! I've hidden my comment above.

EkShunyam commented 10 months ago

Here to say - i loved quarto - its crisp and simple plus i love how engaged you are with the community, explaining with such long and helpful answers

thank you :)