2  Positron and Quarto: A Unified Multi-Language Workflow

Positron is the next-generation data science IDE introduced by Posit (formerly RStudio) to supersede the RStudio IDE. This shift reflects Posit’s broader strategy to support multiple programming languages (notably R and Python) under one roof. In 2022, RStudio rebranded itself as Posit PBC, signaling a new direction toward a more language-agnostic approach. In parallel, Quarto has emerged as a language-agnostic successor to R Markdown (RMD). Quarto is an open-source scientific and technical publishing system that unifies and extends the functionality of the R Markdown ecosystem, adding native support for multiple languages like Python and Julia in addition to R. Together, Positron and Quarto provide an integrated environment for reproducible research, combining code, results, and prose across languages in a single workflow.

Quarto is a stand-alone command-line tool (not an R package) that Positron bundles and supports out-of-the-box. Positron’s integration ensures that users can create, edit, and render Quarto documents seamlessly without manual installation of Quarto or its dependencies. This chapter will explore how to work with Positron and Quarto, updating terminology and technical details from the RStudio/R Markdown era to the new Positron/Quarto ecosystem. We will examine Quarto’s document structure, demonstrate multi-language code chunk execution, discuss Positron’s R and Python integration (including the Python console and environment management), and highlight best practices for reproducible analysis in this modern environment. The academic tone and instructional clarity are maintained throughout, with references provided in APA style to relevant documentation and sources.

2.1 From RStudio and R Markdown to Positron and Quarto

Positron vs. RStudio

Positron retains the familiar feel of RStudio but is built as an extensible, polyglot IDE on the Visual Studio Code framework. RStudio was historically centered on R, featuring a single R process for its console and tools tightly coupled to the R language. In contrast, Positron is designed from the ground up to handle multiple languages (especially R and Python) with first-class support for each. Under the hood, Positron runs R and Python in separate processes (kernels), enabling the IDE to host multiple interpreter sessions concurrently. This architecture means that if R crashes, Positron itself does not crash (unlike RStudio, where the IDE was bound to one R process). It also means users can easily switch between different versions of R and even different languages with a couple of clicks. Posit’s decision to rebrand and develop Positron underscores a strategic move to a cross-language platform, acknowledging that modern data science often mixes R with Python and other tools. Positron is built on open-source VS Code, inheriting its extensibility and familiar interface elements (e.g. a command palette, integrated terminal, source control integration) while offering a tailored experience for data science workflows.

Quarto vs. R Markdown

Quarto builds upon the concepts of R Markdown, unifying various extensions (e.g. rmarkdown, bookdown, xaringan) into one consistent system. Like R Markdown, Quarto allows users to intermix narrative text with code and results in a single document for transparent, reproducible analysis. However, Quarto is explicitly language-agnostic: whereas an R Markdown document (.Rmd) is executed within an R session (with optional Python via the reticulate engine), a Quarto document (.qmd) natively supports multiple programming languages and can execute in different computational engines. In fact, Quarto was designed to be a standalone tool (installed separately from R) that can run with or without R. As Wickham et al. note, Quarto “unifies the functionality of many packages from the R Markdown ecosystem… into a single consistent system” and “reflects everything that was learned from expanding and supporting the R Markdown ecosystem over a decade,” including built-in support for Python and Julia. Many features that required additional packages in R Markdown are built into Quarto (for example, publishing websites or presentations, managing citations, etc., are handled by Quarto’s unified CLI and configuration). Quarto uses Pandoc under the hood for document conversion, just as R Markdown did, but the rendering process is now orchestrated by the Quarto CLI instead of the R rmarkdown package. In RStudio, one would “Knit” an R Markdown document; in Positron, one “renders” or “previews” a Quarto document – effectively the same concept of executing code and generating output, but via Quarto’s system.

Notably, R Markdown’s core syntax carries over into Quarto with some improvements. Quarto still uses Markdown for prose and fenced code blocks for code, but it standardizes how code cell options are specified. Quarto encourages using YAML-like options within chunks (preceded by #|) for clarity. This new syntax replaces some of the old knitr chunk option notation. For example, a Quarto code chunk in R might look like:


::: {.cell}
::: {.cell-output-display}
![](chapter2_files/figure-html/fig-cars-1.png){#fig-cars width=100%}
:::
:::

Here, the chunk is labeled fig-cars and the code is hidden from the output (echo = false), using #| lines inside the chunk. Quarto still recognizes the older chunk option format (e.g., {r echo=FALSE}), but the YAML-style options improve readability and consistency across languages. We will see more on multi-language chunk syntax in subsequent sections.

In summary, Quarto generalizes R Markdown’s literate programming paradigm beyond R, and Positron provides the development environment to leverage that paradigm smoothly with multiple languages. This chapter assumes you are familiar with the basic idea of combining narrative and code (as in R Markdown) and now focuses on how this is achieved in Positron with Quarto.

2.2 Quarto Document Structure and Syntax

A Quarto document (.qmd file) has a structure very similar to an R Markdown document, consisting of three main components:

  1. YAML header (optional): Metadata at the top of the file (enclosed by --- lines) specifying the title, author, date, and output format(s), among other options. For example:

    ---
    title: "My Analysis"
    author: "Jane Doe"
    date: 2025-07-08
    format: html
    ---

    This header declares that the document should be rendered to HTML format. Quarto’s YAML fields overlap with those of R Markdown (title, author, date, output, etc.) but also include Quarto-specific options. For instance, a Quarto project can use a _quarto.yml for global options, and you can specify multiple output formats or profiles for rendering.

  2. Code chunks: Sections of executable code fenced by triple backticks and a language identifier. For example, an R chunk begins with {r} and a Python chunk with {python}. Quarto supports many languages (R, Python, Julia, JavaScript/Observable, Bash, etc.), making it truly multi-language. Within a Quarto document, you can intermix these chunks. Inline code is also supported using syntax similar to R Markdown. For instance, in an R-enabled Quarto document you can insert an inline R expression with 4 to dynamically include results in text. Quarto also supports inline expressions for other languages (e.g., using Jinja2 syntax { } for Python when using certain engines), though often it’s simplest to use R for inline calculations or to structure the document such that non-R outputs are displayed in chunks rather than inline.

  3. Narrative text: Text written in Markdown, which can include headings, lists, formatted text, tables, and so on. Quarto uses Pandoc Markdown, a slightly extended version of Markdown that supports features like citations, cross-references, footnotes, divs/spans with attributes, raw HTML/LaTeX insertion, etc. The narrative text provides context and explanation around the code and results, enabling a literate programming approach to analysis.

Code chunk options: Quarto adopts a unified syntax for chunk options across languages. Options are specified as YAML key-value pairs either in the chunk header or (preferably) as commented lines inside the chunk (using the #| prefix as shown earlier). Common options include echo (whether to display source code in the output), include (whether to include the results in the output), warning (whether to show warnings), fig-cap (figure caption), and many more. For example, in a Python chunk one could write #| warning: false to suppress warnings, or #| fig-cap: "My Plot" to add a caption to a figure. This syntax is consistent across R, Python, Julia, etc., which makes the document format easier to read and write, especially in multi-language contexts. The Quarto documentation provides extensive details on available options and usage. The key point is that Quarto’s document format is a superset of R Markdown’s: anything you could do in R Markdown can be done in Quarto, and Quarto adds more flexibility for other languages plus a streamlined syntax for configuration.

Execution engines: When you render a Quarto document, Quarto automatically chooses an execution engine depending on the content of the file. By default, Quarto uses the Knitr engine (R) if it finds any R code chunks, otherwise it uses Jupyter engines for other languages. In other words:

  • A .qmd file that contains R code will, by default, be executed with Knitr (like an R Markdown document), and if that file also contains Python or other languages, Knitr will delegate those chunks to the R reticulate package for execution.
  • A .qmd file that contains only Python chunks (and no R chunks) will use a Jupyter Python kernel by default.
  • If a document mixes R and Python chunks, Quarto’s default is to use the Knitr engine with reticulate (running all code in a single R process and calling Python from R). This allows R and Python to share state during the render via reticulate.

Reticulate (Allaire, Ushey, & Tang, 2018) is an R package that provides an interface to Python, enabling an R session to start a Python interpreter, execute Python code, and exchange data between R and Python seamlessly. When Quarto uses reticulate (through Knitr) to execute Python chunks, variables can be shared between R and Python. For example, if an R chunk creates a data frame df, a subsequent Python chunk can access that object via r.df, and if Python creates an object x, an R chunk can retrieve it via py$x. This is possible because reticulate embeds a Python session within the R process, allowing bi-directional object access. Using this mechanism, Quarto ensures that in a single document render, your R and Python chunks can work together closely. (Under the hood, Knitr detects the Python chunks and uses reticulate’s Python engine to run them.)

Quarto also allows overriding the default engine. You can explicitly request the Jupyter engine or the Knitr engine in your document YAML, using execute: engine: jupyter or execute: engine: knitr. For instance, advanced users might choose engine: jupyter in a mixed-language document, which would run R and Python in separate processes (e.g., an R kernel and a Python kernel). In that case, R and Python would not share variables or state (since they’re in different sessions), but it can be useful for replicating a Jupyter Notebook environment or using a specific Python environment isolated from R. In general, the default behavior (Knitr + reticulate for R+Python documents) is convenient for most use cases, providing a unified execution where necessary, and the ability to handle multiple languages is mostly automatic and behind-the-scenes.

2.3 Interactive Multi-Language Development in Positron

One of the strengths of using Positron (as opposed to a plain text editor or older RStudio) is its rich support for interactive execution of Quarto documents, even when they contain multiple languages. Positron integrates the Quarto extension (for VS Code) which provides commands and keyboard shortcuts to run cells (code chunks) or even individual lines of code within a chunk. This works similarly to RStudio’s notebook mode, but now extends to Python and other languages in addition to R.

Running code chunks: In Positron’s source editor, each Quarto code chunk has a run button (a play icon) at the top. You can also execute a chunk via keyboard shortcut (for example, Ctrl+Shift+Enter, analogous to RStudio’s Ctrl+Shift+Enter for knitting a single chunk). When you run a chunk, Positron automatically sends the code to the appropriate interpreter session based on the chunk’s language. Positron is capable of managing multiple interpreter sessions at once (e.g., an R session and a Python session). At any given time, one interpreter is considered the active session, which is where code executes by default if you send it line-by-line. If you run an R chunk and an R session is already active, the code runs there; if no R session is active, Positron will launch one. Similarly, running a Python chunk will use or start a Python session as needed. This context switching is handled behind the scenes, so each chunk executes in an interpreter for its respective language.

The result is a fluid interactive experience: you can step through a Quarto document chunk by chunk, even if successive chunks are in different languages, and see results immediately. For example, you might run an R chunk that loads data, then run a Python chunk that analyzes that data. During interactive development, these chunks run in separate processes (one in R, one in Python), so unlike the final render, the R and Python objects are not automatically shared between chunks. If you need to share data between languages interactively, you would have to do so explicitly (for instance, writing data to a file or using copy-paste via the clipboard). However, when you eventually render the document (using Quarto with reticulate), those language bridges will be honored in the final output.

Positron’s interface helps you keep track of which interpreter is active. The console pane in Positron clearly indicates whether it’s an R console or a Python console (and shows the version or environment name). For instance, if you execute an R chunk, you’ll see the output in the R Console tab; if you then execute a Python chunk, the focus may switch to a Python Console tab showing the Python output. Plots generated by R code appear in the Plots/Viewer pane (just like in RStudio), and plots from Python (e.g., via matplotlib or seaborn) will appear in the plots pane when the Python session is active. Figure 1 (conceptual) illustrates this: imagine the source editor (middle) showing a Quarto document with an R chunk followed by a Python chunk; the right-side console and plots panes update according to the language – R output shown when the R chunk runs, and then a Python console with its output and a new plot when the Python chunk runs.

(Figure 1: Positron running a Quarto document with mixed R and Python chunks. The output from the Python chunk (including a plot) is shown in the Python console and Plots pane, demonstrating how Positron integrates multi-language results into the IDE interface.)

By default, Positron displays chunk output in the console and plot panes (rather than inline in the editor). This behavior is similar to the traditional RStudio layout, where code is in the editor and results appear in the console/plots area. If you prefer notebook-style inline output, note that the Quarto extension in Positron does not yet support persistently showing execution results interleaved in the editor (except during an official render/preview). You will typically use the Quarto Preview to see a fully rendered document with all results in place. During interactive work, you use the console and other panes to examine outputs. (It’s possible that as Positron evolves, more inline interactivity will be supported, but as of this writing, the division between editor and console output remains.)

Positron console vs. terminal: Positron provides both a Console pane (for language interpreters) and a Terminal pane (for command-line shell access). The Console pane hosts interactive sessions for R, Python, and potentially other languages. You can have multiple consoles active – for example, an R 4.2 session and a separate Python 3.11 session – and switch between them using the interpreter picker in the IDE. Each console is an independent workspace (for R, it’s like separate R instances; for Python, separate processes or virtual environments). Standard features like command history, auto-completion, and help queries (using ?func in R or help(func)/func? in Python with IPython) work in these consoles. The Terminal pane, on the other hand, gives you direct shell access (e.g., a Bash prompt on Linux/Mac or PowerShell on Windows) similar to RStudio’s Terminal tab. This is useful for tasks like managing packages with pip or conda, using git version control, running shell scripts, etc., without leaving the IDE. Because Positron inherits VS Code’s capabilities, you can open multiple terminal tabs as well. The presence of both consoles and terminals means you have a full range of interactive and system-level access, which reinforces reproducible workflows (e.g., you can document and run a shell command to download data as part of your analysis, all within the Positron project).

2.4 R and Python Integration in Positron

Positron’s ability to work with R and Python side by side is a major advancement for bilingual data science workflows. Here we detail how Positron manages these integrations under the hood and how you, as a user, can control and optimize them.

Multiple interpreter sessions: Unlike the classic RStudio IDE which allowed only one R session per window (and only rudimentary support for another language via reticulate or by using separate tools like VS Code for Python), Positron can host multiple concurrent sessions for R and Python. You can even have more than one R session at a time. Positron’s Interpreter Picker (at the top-right corner of the IDE) is the control center for these sessions. It shows the currently active interpreter (e.g., “R 4.3.1” or “Python 3.11 (venv-myenv)”) and allows you to switch or start new sessions. For example, you could start an additional R session with a different R version, or switch to a different Python environment, all without leaving the project. This is especially useful when your Quarto document or project might require one set of packages in R and another set in Python. Positron’s interface was designed with this polyglot scenario in mind; it gives equal status to R and Python, which means robust code completion, syntax highlighting, linting, and debugging tools for both languages side by side.

Interactive vs. rendered execution: It’s important to understand the distinction between interactive work in Positron and the final rendering of a Quarto document. When you render a Quarto document that mixes R and Python, as described earlier, Quarto/Knitr runs everything in one R process using reticulate for Python. This means during the render, R and Python share an environment (you can pass objects back and forth). However, when you are working interactively in the Positron IDE, the R console and Python console are separate processes. For example, if you interactively run an R chunk that creates a variable df and then interactively run a Python chunk that tries to use df, the Python session will not know about df (because in the IDE, it’s running in a separate Python process). This can be confusing at first if you’re used to the behavior on render. To bridge this gap during interactive work, you would need to explicitly transfer data. One way is to write data to a file in one language and read it in the other. Another way, if you want to mimic the reticulate behavior interactively, is to use reticulate functions in R to assign Python objects or pull R objects. For instance, in an R console you could do reticulate::py_assign("df", df) to send an R data frame to Python, or use reticulate::py$df in R to access a Python object (assuming reticulate is loaded in the R console). These are advanced maneuvers; in practice, a simpler pattern is to keep most of your work self-contained in one language at a time when exploring, and rely on Quarto’s unified execution when you need the cross-language integration in the final document.

In many Quarto analyses, one language is primary and the other is used for a specific task. For example, you might do data cleaning and visualization in R, but call a Python chunk to use a machine learning library, then return to R for further analysis. In such cases, it’s often sufficient to exchange data via file or ensure that the Python chunk writes its results (e.g., predictions) to a CSV which R then reads. This approach maintains a clear boundary and avoids tricky state sharing issues. If deeper integration is needed (e.g., sharing an in-memory data frame), you can rely on reticulate during render, and perhaps test the combined workflow by actually rendering the document rather than only running chunks interactively. Positron makes it easy to render (with the Preview button) as you develop, so you can catch any cross-language issues by doing a trial render periodically.

Language-specific IDE features: Each language interpreter in Positron brings its own set of tools in the IDE. For R, Positron provides the familiar Environment pane (listing R objects), a Plots pane for graphs, the Packages pane, and the Help pane for documentation. For Python, Positron offers analogous capabilities: a Variables pane that can display Python variables (e.g., NumPy arrays, pandas DataFrames, etc.), a plots viewer for Python graphics, and integration with IPython for rich output and help (so you can use ? or help() to get documentation, and it will display in the console). Autocomplete and IntelliSense are available in both R and Python editors. In Python, Positron uses the Python language server (and if available, IPython completions) to suggest code completions and object attributes. In R, it uses the same completion mechanism as RStudio did. Positron also includes a Data Viewer (sometimes called Data Explorer) that works for both R and Python data frames. If you have a pandas DataFrame in Python, it will appear in the Variables pane and you can click to view it in a spreadsheet-like viewer (similarly to using View() in R). This parity of features is a significant improvement over the RStudio era, where Python support was minimal. In Positron, a Python user gets almost the same level of IDE support as an R user. In fact, Positron can even open Jupyter Notebooks (.ipynb files) in a dedicated Notebook Editor interface if desired, allowing you to work with notebooks directly. Overall, Positron’s design ensures that whether you write R code or Python code, you have a rich set of tools for writing, running, and debugging that code.

2.5 Python Terminal Access and Environment Management

Working with multiple languages means managing multiple package ecosystems and interpreter installations. Positron, along with the Quarto ecosystem, embraces best practices for environment management to ensure reproducibility.

Python environments: Positron automatically discovers Python installations and virtual environments on your system. It supports common environment management systems including Python’s built-in venv, Conda (conda or mamba environments), and pyenv, among others. When you open a project in Positron, the IDE will scan for any virtual environment associated with the project (for example, if your project folder has a .venv/ directory or an environment.yml file). It will also list any global environments or Conda envs it knows about. In the interpreter picker menu, you might see entries like “Python 3.11 (venv my_project_env)” or “Python 3.10 (Conda env: analysis-env)” as options. Positron’s philosophy is to encourage project-specific environments, in line with Python community practices. If no dedicated environment exists for your project, you can create one directly from Positron: the Command Palette has a command Python: Create Environment that will guide you through creating a new virtual environment (or Conda env) in your project folder. Once created, Positron will automatically switch to using that environment for the Python interpreter.

Managing Python packages in these environments can be done via the Terminal (e.g., pip install <package> or conda install <package>), or through any package manager you prefer. Quarto itself doesn’t enforce a particular Python environment, but when rendering a document, it will use the Python that is on the system PATH (or the one specified in Quarto’s settings). On Positron, because you likely launched the Quarto render from within the IDE, it inherits the environment of the active Python interpreter. If Quarto ever has trouble finding the correct Python, you might get an error. For instance, an issue was reported on Windows where Quarto tried to call python3.12.exe and failed because that executable name didn’t exist by default. The solution in that case was to ensure that Python 3.12 was installed and accessible (or to create a symlink/alias so that python3.12.exe points to the actual Python). In general, make sure the Python you intend Quarto to use is available. On Linux/Mac, this often means having a python3 command in PATH. On Windows, Quarto might look for python.exe or specific versioned executables. You can configure Quarto via a quarto.ini file or environment variables if you need to point it to a specific Python path (the Quarto documentation details this).

One useful R-side tool for reproducibility is the {renv} package, which can also manage Python environments. The renv R package (Ushey, 2021) primarily captures R package versions, but it has functionality to embed a Python requirement (for example, renv::use_python() can help set up a project-local Python and lock its dependencies). If you use renv in an R project that also uses Python, you can end up with an renv.lock file that records both R packages and Python packages required, which is highly useful for sharing your project or deploying it (e.g., on Posit Connect).

R versions and libraries: Positron supports having multiple versions of R installed on the same system. On startup, it will search common installation directories and list all discovered R versions (R 4.2 and above, since Positron currently requires R >= 4.2.0). If you have, say, R 4.2.3 and R 4.3.1 installed, both will appear as options in the interpreter picker. You can switch between them or even run them concurrently in separate consoles. While R doesn’t have “virtual environments” in the same sense as Python, you can emulate project-specific libraries using tools like renv. It’s a best practice to use renv::init() in your project to isolate an R library for that project and create an renv.lock file. Positron works seamlessly with renv – when you open a project, if an renv environment exists, you can restore it to get the exact package versions recorded. This ensures that your R code in the Quarto document runs with the intended package versions. Another tool, rig (Csárdi, 2022), is an R version management utility for Mac and Linux that Posit recommends for maintaining multiple R versions side-by-side. If you install R through rig (which gives you binary names like R-4.3 for specific versions), Positron will detect those. On Windows, you can simply install multiple Rs and Positron will pick them up from the Windows Registry or default install folders.

Ensuring reproducibility: Regardless of environment management tool, it is crucial to document your computational environment for reproducibility. Here are some best practices:

  • Use project files and relative paths: Positron still uses the concept of a Project (with a .Rproj file, though it’s optional). It’s wise to keep your Quarto document and data in a project directory and avoid setting a working directory in code. Use relative paths within the project. Quarto, by default, will treat the document’s folder as the base directory for execution, unless you override with execute: dir: in YAML.

  • Record dependencies: For R, an renv.lock file captures package versions. For Python, you might maintain a requirements.txt or environment.yml. Quarto has a feature where if you include a requirements.txt alongside your document, Posit Connect (when publishing) will install those requirements. Even if you’re not using Connect, it’s good to have a record of needed Python packages (perhaps in your project README or in comments). If you used Conda, exporting an environment.yml (via conda env export) is helpful.

  • Isolate and test: Because Quarto documents run from a clean session on render, you should periodically restart your R and Python sessions in Positron (there are commands to restart the consoles) and try rendering your document to catch any hidden dependencies (like variables left in environment, or packages loaded but not listed). This mimics the “Knit from scratch” rule that was always recommended for R Markdown: the document should create everything it needs.

  • Coordinate with collaborators: If others will run your Quarto document, ensure they know which R and Python versions to use. Positron’s project settings can lock an interpreter (for instance, the .Rproj can specify which R version to use), and you might include a note in the document or README about required versions (e.g., “Analysis performed with R 4.2.3 and Python 3.11”). This helps avoid discrepancies due to language version differences.

By following these practices and using Positron’s environment management features, you can substantially reduce “it works on my machine” problems and make your analysis more reproducible.

2.6 Rendering and Publishing with Quarto in Positron

Writing and running chunks interactively is only part of the workflow; ultimately, you will render your Quarto document to produce a final output (HTML report, PDF article, slides, etc.). In Positron, rendering is integrated via the Quarto extension. There are a few ways to render or preview:

  • Quarto Preview button: When you have a .qmd file open in Positron, you’ll notice a Render or Preview button (often a small book or document icon with a magnifying glass) in the editor toolbar. Clicking this will run quarto preview on your document. By default, this generates the output and opens a preview in the Positron interface (usually in the Viewer pane or a new tab).

  • Command Palette: You can also use the VS Code Command Palette (Ctrl+Shift+P) and choose Quarto: Preview or Quarto: Render. The difference is that “Preview” typically stays running and will watch for changes (if you have the --no-watch turned off, it will live reload on content changes), whereas a straight render will just compile the document once.

  • Keyboard shortcut: There may be a keyboard shortcut for render (in RStudio it was Ctrl+Shift+K). In Positron, check the keybindings – often it’s the same or you can set it.

When you trigger a preview, Positron will call the Quarto CLI under the hood (Positron bundles Quarto, so it comes with the Quarto binary). Quarto will then execute all the code in the document and convert the results to the specified output format. If the YAML had format: html, it will create an HTML file; if multiple formats were listed (say HTML and PDF), Positron might ask which format to preview or default to the first. You can explicitly choose a format by using the Quarto: Preview Format command and selecting (for example) PDF.

During rendering, you can see the progress and any messages in the Positron Console. If an error occurs (such as an R error in a chunk, or a missing Python package), the render will stop and an error message will be shown. These error messages can sometimes be cryptic, but they generally point to the chunk and line where the problem happened. For instance, an R error will show the R traceback in the console. A Python error might show a stack trace or just the exception message. If Quarto itself has an issue (for example, can’t find a required program), it will output an error with details. The earlier example of Quarto not finding python3.12.exe is such a case – Quarto halted because it expected a python3.12 command. In such a scenario, you would resolve the environment configuration (e.g., install the needed Python or adjust Quarto settings) and then render again.

One convenient feature in Positron is Render on Save. You can configure your Quarto document to automatically re-render every time you save the file. To enable this, add to the YAML header:

editor: 
  render-on-save: true

Alternatively, there’s a setting in the Quarto extension or a command to toggle render-on-save. This is very handy for rapid preview cycles: as you make small edits to text or code and hit save (Ctrl+S), the preview refreshes to show the updated result. Be cautious with this on very long documents or computationally heavy documents, as it will re-run everything on each save (which could be slow). But for light documents or during early drafting, it provides immediate feedback.

After rendering, the preview appears in Positron. For an HTML output, Positron’s viewer is essentially a mini web browser. You can scroll through and see that all your code results (figures, tables, etc.) are in place. This is the same output you would get by knitting in RStudio or by opening the HTML in an external browser. If you prefer, you can open the output in an external browser (there’s usually a button for that in the preview pane). PDF outputs will open in Positron’s PDF viewer, or externally if you choose. Word outputs would open in Word if you have it, since the preview might just offer to open the .docx.

Quarto can also render entire projects, websites, or books. If your project is more complex (multiple .qmd files), you can still use Positron to preview the whole site or book (for example, if you open _quarto.yml of a Quarto website, the preview button might build the site). For most single documents, the process is straightforward.

Once you have a finished output, you may want to publish or share it. Positron doesn’t have a one-click “Publish” button like RStudio did for RPubs or Connect by default (as of now), but you can still publish Quarto outputs easily. The typical route for publishing a Quarto document to Posit Connect (the successor to RStudio Connect) is to use the Posit Connect publishing approach: you can publish the rendered document or the source and let Connect render it. Since this chapter is focusing on authoring, we won’t delve deeply into publishing. However, it’s worth noting that Quarto is well-supported on Posit Connect. You can push a Quarto document (with its .qmd and any supporting files) to Connect and it will render there (Connect will use the lock files and requirements.txt if provided to recreate the environment). Alternatively, you can render to HTML and just share the HTML file (for example, via GitHub Pages or any static site host). Quarto even has a built-in web server for preview that you can use to serve your HTML (for live previews or sharing locally).

Finally, if your goal is a PDF for an academic publication or a Word document for a report, Quarto’s output should be ready to go once rendered. Make sure to use Quarto’s citation features if you need bibliographies (Quarto can read a .bib file and render citations in APA or other styles, just like R Markdown’s citation functionality). All these aspects — environment management, accurate rendering, and including references — contribute to the reproducibility and professionalism of your final report.

2.7 Best Practices in the Positron-Quarto Ecosystem

To conclude, here are some best practices and tips for using Positron and Quarto effectively, updated from earlier RStudio/R Markdown guidelines:

  • Reproducibility and Project Orientation: Continue to use a project-oriented workflow. In Positron, this could mean opening a directory as a Workspace (Positron emphasizes opening a folder, which serves a similar role to an RStudio Project). Keep all your analysis files (Quarto docs, scripts, data) in this folder. Avoid using setwd() in your code; instead rely on project structure. Use version control (git) if possible to track changes. Record session information when publishing (you can include the output of sessionInfo() in R and sys.version/pip freeze in Python as an appendix in your document to log the environment details). Positron will not automatically save your workspace (.RData) between sessions (a design choice to encourage reproducibility), which is good – it forces you to create your results from code, not from clicking around.

  • Quarto Document Structure: Keep your Quarto document well-organized. Use section headings (with #, ##, etc.) to structure the narrative and analysis. The example in this chapter demonstrates using multiple levels of headings to separate topics. Write descriptive section titles (e.g., “Data Cleaning”, “Statistical Modeling Results”, “Discussion”) so that readers and collaborators can navigate easily. Use Quarto’s cross-referencing feature for figures and tables: give your important chunks labels (e.g., #| label: fig-results) and then you can refer to “Figure ?fig-results shows…” in your text; Quarto will auto-number and link it. This makes your report more professional and easier to read. Also, take advantage of Quarto’s citation integration for academic writing – manage your sources in a .bib file and cite with [(key?)] syntax, Quarto will generate a references section automatically.

  • Code Chunk Management: Document your code chunks. Start chunks with a brief comment if necessary to explain what the code does (especially if it’s not obvious). Use chunk options to control output: for example, set echo: false for chunks that generate figures or tables that don’t need to show the underlying code to the reader. Conversely, for teaching materials or tutorials, you might echo: true but eval: false to show code without running it (Quarto even has an echo: fenced option to display chunk fences and options in output). Quarto supports caching of results (cache: true option on a chunk) similar to knitr, which can speed up re-rendering by skipping expensive computations if the code hasn’t changed. Use caching cautiously and document when you do (as cached results can sometimes lead to outdated output if you forget to reset cache). Another tip is to break long computations or large outputs into separate chunks or even separate scripts that you call from Quarto (for example, source an R script or import a Python module) to keep the document tidy.

  • Multi-language Considerations: Plan your multi-language workflow to minimize friction. If using both R and Python, decide which language is primary for the data and which is supplemental. Perhaps use R for data manipulation and Python for a specific machine learning model (or vice versa). Keep the interface between them as simple as possible – e.g., read/write CSV or use reticulate to hand over a data frame if you must. Document in your text when you switch languages (“Next, we use Python’s scikit-learn to train a model on the data prepared above…”), so the reader is aware of the context shift. Remember that Quarto’s default execution will allow R-Python interaction via reticulate, but in Positron’s interactive mode you won’t see that interaction live. To avoid confusion, sometimes it’s acceptable to separate the analysis into multiple documents: one Quarto doc in R, another in Python, especially if they don’t need to share state and you plan to combine results in a report. Quarto projects (like books or websites) can include chapters written in different languages seamlessly.

  • Use of Positron Tools: Leverage Positron’s modern IDE features to their fullest. The Command Palette (Ctrl+Shift+P) is extremely powerful for discovering functionality – for instance, typing “Quarto” will show you all Quarto-related commands (render, create project, etc.), typing “Python” will show Python commands (create environment, select interpreter), and so on. Positron also comes with the Posit AI Assistant (if enabled) that can help with code completion or suggesting documentation (this feature might evolve, but it’s there as of 2025). The Extensions marketplace (OpenVSX in Positron’s case) is available if you want to install additional tools; for example, you might install a spell checker for Markdown, or a bracket colorizer, etc. (Positron allows most VS Code extensions that are relevant, except it uses OpenVSX repository due to licensing). Keep an eye on the Posit documentation/blog for new features. Positron is still relatively new, and features like visual editing (WYSIWYG editing of Quarto) or enhanced notebook UI may appear in future updates. By staying updated and engaged with the Posit community forums, you can learn tips and troubleshoot issues that others have encountered (for example, if you run into a Quarto rendering quirk in Positron, chances are someone on the Posit community or Stack Overflow has posted about it, as we saw in the case of the Python executable issue).

In essence, working with Positron and Quarto might feel like a significant change if you’re coming from RStudio and R Markdown, but it’s a change built on years of experience with those tools. Many best practices carry over (script everything, document everything, prefer explicit code over manual steps), and the new tools expand the possibilities (multiple languages, better IDE integration for Python, etc.). Embrace the robust features, but also remain mindful of reproducibility fundamentals.

2.8 Conclusion

Positron and Quarto represent a modern, flexible approach to reproducible data science, carrying forward the spirit of RStudio and R Markdown but extending it to a multi-language world. In this chapter, we updated references to RStudio with Positron and R Markdown with Quarto, reflecting the evolving landscape of tools. We highlighted how Positron natively handles R and Python side by side – from concurrent interpreter sessions and multi-language code execution to integrated environment management – and how Quarto provides a language-agnostic document format that encapsulates years of lessons from the literate programming community.

Researchers and analysts can now seamlessly mix R and Python (and other languages) in a single project, using each for what it does best, and still produce a cohesive, single-output report or publication. The Positron IDE supports this workflow by offering a familiar yet enhanced interface where one can write and run code in different languages with consistent support (autocompletion, debugging, visualization) without resorting to awkward workarounds. Meanwhile, Quarto ensures that the final product – be it a journal article, a business report, or a slide deck – is reproducible and shareable, with support for multiple output formats and the inclusion of all source code and narrative.

The transition from RStudio/R Markdown to Positron/Quarto does introduce some new concepts and syntax. There is a learning curve: for example, using #| for chunk options, managing two consoles, or configuring Python environments. However, the core principles of literate programming and reproducible research remain the same. By adopting Positron and Quarto, you are aligning with a future-proof workflow that acknowledges the multi-language reality of today’s data science. Posit (2024) has made it clear that Positron is the future of their data science IDE, built to cater to an audience that uses R and Python (and perhaps Julia, SQL, etc.), rather than just R. Likewise, Quarto’s rise signals a commitment to an open-source, interoperable framework for technical communication that is not tied to a single language.

Positron and Quarto together provide a powerful, cohesive ecosystem for modern data analysis and communication. By following the best practices outlined above and leveraging the capabilities of these tools, you can ensure that your analyses are not only technically sound, but also elegantly presented and easily reproducible by others – whether they choose to run your code in R, Python, or any other supported language. This combination of robust, language-flexible tools and solid workflow habits will serve academic and professional projects well in the years to come.

References

  • Allaire, J. J., Ushey, K., & Tang, Y. (2018). reticulate: Interface to “Python”. R package version 1.9. Retrieved from CRAN:

  • Posit PBC. (2025). Positron IDE Documentation. Retrieved from Posit: Positron: Interpreter Management and Environment Discovery (multiple sections).

  • Quarto Project. (2023). Quarto Documentation. Retrieved from Quarto.org: Execution Options, FAQ for R Markdown Users.

  • Roe, T. (2024, December 5). Positron vs RStudio – is it time to switch? Jumping Rivers Blog. Retrieved from .

  • Wickham, H., Grolemund, G., & Posit Team. (2023). R for Data Science (2e) – Chapter 28: Quarto. Retrieved from https://r4ds.hadley.nz/quarto.html .

  • Stack Overflow. (2024, March 6). Issues Running Code Chunks in Quarto on Positron. Retrieved from https://stackoverflow.com/questions/79489177