diff --git a/pages/quarto.qmd b/pages/quarto.qmd index 4c062d4a..7fff8f39 100644 --- a/pages/quarto.qmd +++ b/pages/quarto.qmd @@ -46,6 +46,19 @@ website](https://quarto.org/docs/faq/rmarkdown.html) for more in-depth discussions regarding Quarto/R Markdown (dis-)similarities. ::: +::: {.callout-tip title="Python and R paths"} +To be sure that Quarto uses the Python and R installations in the `quarto-env` +environment, you can set the environmental variables `QUARTO_PYTHON` and `QUARTO_R` +to the paths of the Python and R executables in the `quarto-env` environment. + +Activate the `quarto-env` environment and run the following commands in the +terminal: + +```bash +export QUARTO_PYTHON=$CONDA_PREFIX/bin/python +export QUARTO_R=$CONDA_PREFIX/bin/R +``` +::: ## The basics Let's start with creating basic Quarto document that we can work with. @@ -55,7 +68,7 @@ Let's start with creating basic Quarto document that we can work with. Quarto documents are just plain text files with the `.qmd` extension. Create a new file called _e.g._ `quarto-tutorial.qmd` and copy the following into it: -```yaml +```{.yaml filename="quarto-tutorial.qmd"} --- title: "Untitled Quarto Document" author: "Jane Doe" @@ -79,7 +92,7 @@ markdown: - Add some text into your Quarto document (including an empty line between the YAML header and the text), _e.g._ the following: -``` +```{.markdown filename="quarto-tutorial.qmd"} This is my first Quarto document! # This is a header @@ -99,11 +112,13 @@ above command from the command line if you prefer. Open your new `quarto-tutorial.html` file that was created and see what it looks like. It's only markdown content so far, so let's add some R code using a *code -chunk*: +chunk*. Add the following to the `quarto-tutorial.qmd` file: +````{.markdown filename="quarto-tutorial.qmd"} ```{{r}} Sys.Date() ``` +```` Notice that we delimit the code chunk from the rest of the document's contents using three backticks (\`\`\`) and specify the R language using curly brackets @@ -113,9 +128,11 @@ using three backticks (\`\`\`) and specify the R language using curly brackets You can also name chunks by adding it after the language: -```{{r}} +````{.markdown filename="quarto-tutorial.qmd"} +```{{r date}} Sys.Date() ``` +```` This is useful for debugging when something has gone wrong, since it'll be easier to see exactly which code chunk an error happened (instead of just @@ -123,7 +140,7 @@ showing the chunk as a number). We can also get _in-line code_ using `{{r}} `, like so: -``` +```{.markdown filename="quarto-tutorial.qmd"} The current date is `{r} Sys.Date()`. ``` @@ -186,83 +203,35 @@ Switch back to HTML rendering before you move on. ### Languages The examples so far have been using R, but we could just as easily have used -Python. All we have to do is to change our code chunk to specify `{python}` as -language and its content to be the equivalent Python code: +Python. All we have to do is to specify `{python}` as the code chunk language and +its content to be the equivalent Python code. Try adding this to your document and +render it again: +````{.markdown filename="quarto-tutorial.qmd"} ```{{python}} from datetime import date print(date.today()) ``` - -- Change the code chunk to the above Python chunk instead and render your - document again. - -::: {.callout-note title="A note on Python in-line code"} -Quarto support for in-line python code was added in version 1.4, so if you're -using an older version of Quarto simply remove the in-line code example. You -can check your quarto version by running `quarto --version` on the -commandline. As of this writing, the 1.4 version of Quarto can be obtained -from the pre-release page: https://quarto.org/docs/download/prerelease - -If you're using Quarto version 1.4 or higher and want to try the in-line code -example above for Python, change the line to: -``` -The current date is `{{python}} date.strftime(date.today(), format="%Y-%m-%d")` -``` -::: - -So far we've had Quarto automatically determine which language *engine* should -be used, which it detects through the code chunks we've written. We can also do -this explicitly by adding `engine: knitr` or `engine: jupyter` to the YAML -header. - -- Explicitly add `engine: jupyter` to your YAML header and render the document. - -::: {.callout-note title="Making sure your Jupyter engine is recognised"} -Quarto attempts to identify a suitable Jupyter engine for your system when you include Python code chunks. -However, if you want to use Jupyter available in a specific conda environment (_e.g._ your `quarto-env` -environment) you need to take some extra steps. Please visit -[this link](https://github.com/Anaconda-Platform/nb_conda_kernels#use-with-nbconvert-voila-papermill) -and follow steps 1-4. -In the final step, check for the name of the kernel matching your `quarto-env` conda environment, _e.g._ -```bash -$ jupyter kernelspec list -Available kernels: -... - conda-env-quarto-env-py /Users/_files/` directory, refresh the rendered document and see what happens. - - Add the `embed_resources` option and render your document again. + - Add the `embed-resources` option and render your document again. What happened first is that your figures should have disappeared when you deleted the resources directory. Embedding resources and rendering again should @@ -558,8 +530,7 @@ always render them all. The last document-wide option we'll touch on is *parameters*. This is useful for when you want to be able to run the same document with different parameters or -options for some computations. How parameters are specified depends on which -engine you're using. With Knitr you can specify parameters using the `params` +options for some computations. Parameters are specified using the `params` option: - Add the following code to your YAML header: @@ -593,15 +564,7 @@ param:value` flag multiple times, like so: quarto render quarto-tutorial.qmd -P point_size:4 -P ncols:1 ``` -If you're using the Jupyter engine you can instead specify parameters by -designating a single cell as a *parameter cell*, like so: - -```{{python}} -#| tags: [parameters] -point_size = 2 -``` - -You can also specify parameters in a `params.yml` file and instruct quarto to use them with the `--execute-params params.yml` flag when rendering. Note that the parameters must be defined in the document (in the YAML header when using the `knitr` engine, or in a cell when using the `jupyter` engine). Pointing quarto to a `params.yml` file with `--execute-params` only overrides them when rendering. +You can also specify parameters in a `params.yml` file and instruct quarto to use them with the `--execute-params params.yml` flag when rendering. Note that the parameters must be defined in the YAML header, pointing quarto to a `params.yml` file with `--execute-params` only overrides them when rendering. Using parameters is extremely useful when you're using a workflow manager system (_e.g._ Snakemake or Nextflow), since you can easily specify sample-specific parameters from the command line directly from your workflow manager. @@ -675,7 +638,7 @@ which can also be achieved with divisions. When adding a division to slide content we specify the division's content in a manner similar to a code chunk, like in the following example: -``` +```{.markdown filename="quarto-tutorial.qmd"} ## Penguin species ::: {.incremental} @@ -735,7 +698,7 @@ is done with the `{.columns}` and `{.column}` divisions. The former specifies that a section with multiple columns is starting, while the second specifies when each column starts, like so: -```no-highlight +```{.markdown filename="quarto-tutorial.qmd"} :::: {.columns} ::: {.column} @@ -780,7 +743,7 @@ You can also control the order in which fragments appear using the than the order of the code. If you need help or inspiration, click below. ::: {.callout-tip collapse="true" title="Click to show"} -``` +```{.markdown} ## Why Palmer Penguins? ::: {.fragment fragment-index=2} @@ -875,22 +838,169 @@ option or the `callout-appearance` global option. Valid values are `default`, also suppress the callout icons using `icon=false` or `callout-icon: false` in a similar manner. +### Python code + +So far we've used Quarto with R-code chunks, but Quarto also supports Python. +While R-code is executed with the **Knitr** engine, Python code can be executed +using either **Jupyter** or Knitr + the **reticulate** package. + +To try out Python code in Quarto, make a new document called `quarto-python.qmd` +and add the following to it: + +````{.markdown filename="quarto-python.qmd"} +--- +title: "Python in Quarto" +format: html +--- + +This is a Quarto document with Python code! + +```{{python}} +from datetime import date +print(date.today()) +``` + +Here is how you'd use inline code to print today's date: `{{python}} date.today().strftime("%Y-%m-%d")`. +```` + +Save and render the document with `quarto render quarto-python.qmd`. + +You probably saw that Quarto reported: + +```no-highlight +Starting python3 kernel...Done +``` + +This is because Quarto automatically determined that it should use a Jupyter +kernel to execute the code in the document. You can read more about how this works +[here](https://quarto.org/docs/computations/execution-options.html#engine-binding). + +The `quarto-env` conda environment that you installed for this tutorial comes +with the default `IPython` kernel, but you can install additional kernels for +other coding languages or containing specific packages. + +To see which kernels are available on your computer, run `jupyter kernelspec +list` on the command line. If you haven't installed any kernels before you +should just see the `python3` kernel which is the one contained in the +`quarto-env` environment and the one Quarto used to render the document above. + +If you want to explicitly instruct Quarto to use the `python3` kernel you can +add `jupyter: python3` to the document YAML header. However, this requires that +you have the `quarto-env` environment activated. If you activate another conda +environment with the `jupyter` package installed, the `python3` kernel used for +rendering will be the one in that environment. + +To get around this, you can install the kernel in an active conda environment +under a unique name using the following command: + +```bash +python -m ipykernel install --user --name=KERNEL_NAME +``` + +where `KERNEL_NAME` can be any name you want. Try this out with the `quarto-env` +environment. Run: + +```bash +python -m ipykernel install --user --name=quarto-env +``` + +Now specify the kernel name in the YAML header of your Quarto document: + +```yaml +jupyter: quarto-env +``` + +and render the document again. + ### Mixing R and Python -Earlier in the tutorial we showed how to change the language using the `engine` -global option, but there is actually a way to use both R and Python in the same -Quarto document. This is done via the Knitr engine and the `reticulate` R -package, which allows communication between any variables and data you store in -either R or Python code chunks. While this may not be that common of a use-case, -it's still great that it's there for those that want access to it. We won't go -through the details of how this works here, but you're welcome to go and check -out the [official reticulate website](https://rstudio.github.io/reticulate/) for -yourself. - -If you just want to mix R and Python in a single Quarto document without the -interoperability between the languages it's a lot simpler, though. You can -either just install the `reticulate` package (`r-reticulate` in Conda) or -add the `python.reticulate=FALSE` chunk option to the Python chunks. +Another way to execute Python code in Quarto documents is to use the +`reticulate` package in R. This also allows you to use R objects such as +dataframes in Python code chunks and vice versa. The `r-reticulate` conda +package is already installed in the `quarto-env` environment, so you can try +this out directly in the `quarto-python.qmd` document you created above. + +Change the YAML header in `quarto-python.qmd` to instruct Quarto to use the +Knitr engine. The header should look like this: + +```{.yaml filename="quarto-python.qmd"} +--- +title: "Python in Quarto" +format: html +engine: knitr +--- +``` + +Also add the following R code chunk to the end of the document: + +````{.markdown filename="quarto-python.qmd"} +```{{r}} +library("palmerpenguins") +library("reticulate") +data(penguins, package = "palmerpenguins") +penguins <- penguins[!is.na(penguins$body_mass_g),] +head(penguins) +``` +```` + +Render the document again. In the R code chunk we load the penguins dataset, +remove rows with missing values and printed the first few rows. As you can see, +both the Python and R code chunks are executed in the same document. You'll also +notice that the inline Python code could not be executed. This is currently a +limitation of Knitr. + +Now add the following Python code chunk: + +````{.markdown filename="quarto-python.qmd"} +```{{python}} +import pandas as pd +penguins = r.penguins +penguins["body_mass_kg"] = penguins["body_mass_g"] / 1000 +penguins.head() +``` +```` + +and render the document again. + +This code chunk takes the penguins dataframe from R (`penguins = r.penguins`) +and adds a new column with the body mass in kilogram then prints the first few +rows. + +We can also pass the modified dataframe back to R. Add the following code chunk: + +````{.markdown filename="quarto-python.qmd"} +```{{r}} +#| fig-width: 10 +#| fig-height: 5 +#| label: fig-penguins +#| fig-cap: "Penguin weight and bill length" +#| fig-alt: "A scatter plot of penguin weight and bill length" +#| cap-location: margin +library("ggplot2") +penguins_py <- py$penguins +ggplot(penguins_py, + aes(x = bill_length_mm, + y = body_mass_kg, + colour = species)) + + geom_point(size = 2) + + theme_bw() + + labs(x = "Bill length (mm)", + y = "Body mass (kg)", + colour = "Species") + + ggtitle("Penguin weight and bill length") + + theme(plot.title = element_text(hjust = 0.5)) + + scale_colour_manual(values = c("#c1dea0", "#85be42", "#425f21")) +``` +```` + +then render the document again. + +In this code chunk the modified dataframe is passed to R (`penguins_py <- +py$penguins`) and used to create a scatter plot of penguin weight (in kilograms) +and bill length. + +You can read more about the `reticulate` package in the +[documentation](https://rstudio.github.io/reticulate/). ### Citations diff --git a/tutorials/quarto/environment.yml b/tutorials/quarto/environment.yml index 5ab4daa4..66d2ab1a 100644 --- a/tutorials/quarto/environment.yml +++ b/tutorials/quarto/environment.yml @@ -12,4 +12,5 @@ dependencies: - r-rmarkdown - r-reticulate - nb_conda_kernels - - papermill \ No newline at end of file + - papermill + - pandas \ No newline at end of file