6 Quarto
In Your First R Project, you worked with a .qmd file—running code chunks interactively, viewing results in the plots pane, and rendering the document to HTML. This chapter explains Quarto’s syntax and features in depth so you can write your own analysis documents from scratch.
Quarto is a scientific publishing system that lets you combine code, results, and narrative text in a single document. You write analysis scripts as .qmd files—plain text with embedded R or Python code—and Quarto renders them into polished HTML reports with your outputs automatically included.
In the Musser Lab, Quarto documents are the standard format for data analysis because they solve a fundamental problem: keeping your code, your results, and your explanation of those results in sync. When you render a .qmd file, Quarto executes the code fresh and weaves the outputs into the document, so the report always reflects the actual analysis.
6.1 Why Quarto?
6.1.1 Compared to Plain Scripts
A plain .R or .py script is just code. It can produce outputs, but there’s no built-in way to document what the code does, why you made certain choices, or what the results mean. When you share a script, collaborators see the code but not your interpretation. Comments help, but they’re limited—you can’t embed figures, formatted tables, or section headings in a comment.
With Quarto:
- Code and narrative live together — explain what you’re doing as you do it
- Results are embedded — figures and tables appear in the document
- Output is shareable — render to HTML that anyone can open in a browser
6.1.2 Compared to Jupyter Notebooks
If you’ve used Jupyter notebooks (.ipynb), you might wonder why we use Quarto instead. Jupyter is a great tool for interactive exploration, but .qmd files have several advantages for reproducible analysis:
Plain text, not JSON. Jupyter notebooks are stored as JSON with embedded output cells, making them difficult to version control with Git. A small code change can produce a massive diff because the output cells change too. Quarto documents are plain text—diffs show exactly what you changed, and merge conflicts are easy to resolve.
Fresh-session rendering. When you run cells in a Jupyter notebook, results depend on the order you executed them and what’s lingering in memory. It’s easy to have a notebook that “works” only because you ran cell 5 before cell 3 during development. Quarto renders in a fresh session every time, catching hidden dependencies that Jupyter lets slip through.
Positron integration. In Positron, you get the best of both worlds—interactive execution with Cmd+Enter (like Jupyter) plus a persistent console, Variables pane, and Data Viewer alongside your document. You don’t lose the interactive workflow; you gain reproducibility on top of it.
One format, both languages. Quarto treats R and Python as equal citizens. The same .qmd format, chunk options, and rendering pipeline work for both. No need to learn separate tools for each language.
If you’re coming from Jupyter, the transition is straightforward: your code goes in fenced chunks instead of cells, your markdown goes between chunks instead of in markdown cells, and you render the whole document instead of running cells individually. The interactive development experience in Positron feels very similar to Jupyter—you just get reproducibility as a bonus.
6.1.3 Compared to R Markdown
If you’ve used R Markdown (.Rmd), Quarto will feel familiar. The core idea—mixing code, results, and narrative—is the same. Quarto is R Markdown’s successor, developed by Posit (the company behind RStudio) as a unified system that works equally well with R, Python, Julia, and other languages.
| R Markdown | Quarto | |
|---|---|---|
| File extension | .Rmd |
.qmd |
| Language support | R-centric (Python possible but awkward) | Multi-language by design |
| Chunk options | {r, echo=FALSE} |
#| echo: false (YAML-style) |
| Output formats | Documents, some websites | Documents, websites, books, slides, dashboards |
You don’t need to memorize the differences. If you know R Markdown, Quarto works similarly. If you’re new to both, just learn Quarto—it’s the modern standard.
6.1.4 What Else Can Quarto Do?
While we primarily use Quarto for analysis scripts, it’s a general-purpose publishing system. This book was built with Quarto. You can also create:
- Websites — project documentation, lab websites
- Presentations — slides rendered from code (RevealJS format)
- Dashboards — interactive displays of data
See the Quarto documentation if you want to explore these formats.
6.2 The Interactive Development Workflow
Before diving into syntax, understand how you’ll actually work with Quarto documents. There are two modes, and you’ll spend most of your time in the first one.
Interactive development is where the real work happens. You write a chunk of code in your .qmd file, run it with Cmd+Enter (macOS) or Ctrl+Enter (Windows), inspect the output in the Console or Data Viewer, tweak it, run again. Objects you create persist in your R or Python session, so you can build on previous chunks. This feels just like working in a Jupyter notebook or an R console—the .qmd file is your scratch pad, and Positron is your workbench.
[TODO: screenshot of Positron with .qmd open, console showing output, Data Viewer with dataframe]
Rendering is for validation and sharing. When the analysis is complete—or when you want to check that everything works end-to-end—you render the document:
quarto render my_analysis.qmdRendering executes every code chunk in a fresh session (no leftover objects from interactive work) and produces a standalone HTML file. This catches errors you might miss interactively, like relying on an object you created manually but forgot to include in the script.
A typical session looks like this: you open your project in Positron, create or open a .qmd file, and start writing chunks—setup first (libraries, paths), then data loading, then analysis. You run each chunk interactively, checking results as you go. When the analysis feels complete, you render the whole document. If rendering fails (usually a missing object or package), you fix it and render again. Once it succeeds, you commit the .qmd file.
The key insight: interactive mode is for development, rendering is for validation. Always render before committing or sending a report to someone.
6.3 Writing a Quarto Document
A Quarto document has two parts: a YAML header (metadata and rendering options, between --- markers at the top) and a body (Markdown text interspersed with code chunks).
6.3.1 Creating a New Document
To start a new Quarto document in Positron, go to the File Explorer in the left sidebar, right-click inside your scripts/ folder, and select New File. Name it with a .qmd extension (like 01_analysis.qmd). Positron recognizes the extension and gives you Quarto syntax highlighting and the Render button in the toolbar. Start by pasting in the YAML header and setup chunk from the templates below, then begin adding your own sections and code chunks.
6.3.2 Document Structure
Here’s a minimal example:
---
title: "My Analysis"
format: html
---
## Introduction
This analysis examines the relationship between X and Y.
```{r}
library(tidyverse)
data <- read_csv("data/input.csv")
glimpse(data)
```
## Results
```{r}
ggplot(data, aes(x = x, y = y)) +
geom_point()
```When rendered, this produces an HTML file with the title, your text, and the code outputs (the glimpse() output and the plot) embedded. For Python, the only difference is the chunk fence—use ```{python} instead of ```{r}.
6.3.3 The YAML Header
The YAML header controls document metadata and rendering behavior. Here’s what a typical lab analysis header looks like:
---
title: "Phosphoproteomics Volcano Plots"
subtitle: "Tryptamine treatment time course"
author: "Your Name"
date: today
status: development
format:
html:
toc: true
toc-depth: 2
number-sections: true
code-overflow: wrap
code-fold: false
code-tools: true
highlight-style: github
theme: cosmo
fontsize: 1rem
linestretch: 1.5
self-contained: true
execute:
echo: true
message: false
warning: false
cache: false
------
title: "Phosphoproteomics Volcano Plots"
subtitle: "Tryptamine treatment time course"
author: "Your Name"
date: today
status: development
jupyter: python3
format:
html:
toc: true
toc-depth: 2
number-sections: true
code-overflow: wrap
code-fold: false
code-tools: true
highlight-style: github
theme: cosmo
fontsize: 1rem
linestretch: 1.5
self-contained: true
execute:
echo: true
warning: false
cache: false
---The two headers are nearly identical. Python adds jupyter: python3 (which tells Quarto how to run the Python code) and drops message: false (which is R-specific—R packages print startup messages, Python packages generally don’t).
Here’s what the key options do:
statustracks the script’s lifecycle stage (development,finalized,deprecated)—see Project Organizationtoc: trueadds a table of contents, making long analyses navigableself-contained: truebundles everything into a single HTML file you can email or sharecode-tools: trueadds a button to show/hide all code at onceecho: trueshows your code in the output—important for analysis scripts where the code is part of the documentationmessage: false/warning: falsekeeps rendered output clean by suppressing package messages and warnings
For the full list of YAML options, see the Quick Reference tables at the end of this chapter. For a copy-paste template you can use to start new scripts, see Appendix C.
Claude Code can generate a complete YAML header and setup chunk tailored to your analysis.
I’m starting a new R analysis script for differential expression using DESeq2. Set up a QMD with the standard lab header and a setup chunk that loads DESeq2, tidyverse, and here.
Claude will create a .qmd file with the full YAML header, setup chunk with library loading, output directory creation, and provenance tracking—all following the lab conventions described in this chapter.
6.3.4 The Setup Chunk
Every analysis script should start with a setup chunk that loads packages, defines paths, sets options, and captures the git commit hash for provenance tracking.
#| label: setup
#| include: false
# ---- Libraries ----
suppressPackageStartupMessages({
library(tidyverse)
library(here)
})
# ---- Paths ----
dir_data <- here::here("data")
dir_out <- here::here("outs", "01_script_name")
dir.create(dir_out, recursive = TRUE, showWarnings = FALSE)
# ---- Options ----
options(stringsAsFactors = FALSE)
set.seed(42)
# ---- Provenance ----
git_hash <- system("git rev-parse --short HEAD", intern = TRUE)
cat("Rendered from commit:", git_hash, "\n")#| label: setup
# Standard library modules (built into Python)
import subprocess, sys, random
from pathlib import Path
from datetime import datetime
# Third-party packages (installed via conda)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# ---- Project Root ----
# Find the project root by asking Git where the repository starts.
# This lets us build reliable file paths regardless of where the script lives.
PROJECT_ROOT = Path(subprocess.check_output(
["git", "rev-parse", "--show-toplevel"]
).decode().strip())
# Add the project's python/ folder so we can import our own helper modules
sys.path.insert(0, str(PROJECT_ROOT / "python"))
# ---- Options ----
random.seed(42)
np.random.seed(42)
pd.set_option("display.max_columns", None)
sns.set_theme(style="whitegrid")
# ---- Paths ----
out_dir = PROJECT_ROOT / "outs/01_script_name"
out_dir.mkdir(parents=True, exist_ok=True)
# ---- Provenance ----
git_hash = subprocess.check_output(
["git", "rev-parse", "--short", "HEAD"]
).decode().strip()
print(f"Rendered from commit: {git_hash}")The provenance section uses git rev-parse to capture the current commit hash, and the Python version uses it to find the project root. These commands only work if your project is a Git repository. If you haven’t set up Git yet (covered in the Git & GitHub chapter), you can comment out the provenance lines for now and add them back later when your project is under version control.
Both versions follow the same pattern: libraries, paths, options, provenance. The key differences:
#| include: false(R only) — hides the setup chunk from the rendered output. Python setup chunks typically stay visible because the import list serves as documentation.suppressPackageStartupMessages()(R) — prevents the noisy startup messages that R packages print when loaded.here::here()(R) vsPROJECT_ROOT(Python) — both build file paths relative to the project root, not the script location. The R version uses theherepackage; the Python version finds the root viagit rev-parse. See Working Directory and Paths.set.seed(42)— makes random operations reproducible. Python needs two seeds (random.seedfor stdlib,np.random.seedfor NumPy).
6.3.5 Code Chunks
Code chunks are fenced with triple backticks and a language identifier:
```{r}
# R code here
```
```{python}
# Python code here
```Use the #| syntax to set options for individual chunks:
#| label: load-data
#| message: false
data <- read_csv(here::here("data", "input.csv"))The label option names the chunk. This is useful for debugging (error messages reference the chunk label), cross-references (linking to figures), and caching.
Here are the chunk patterns you’ll use most often:
Hidden setup — runs but doesn’t appear in output:
#| label: setup
#| include: false
library(tidyverse)Visible code with clean output — shows code, hides messages:
#| label: load-data
#| message: false
#| warning: false
data <- read_csv("data.csv")Figure with caption — for publication-ready figures:
#| label: fig-volcano
#| fig-cap: "Volcano plot showing differential expression"
#| fig-width: 6
#| fig-height: 4
ggplot(results, aes(x = logFC, y = -log10(pvalue))) +
geom_point()Code shown but not run — for demonstrating syntax:
#| label: example-syntax
#| eval: false
# This code is displayed but not executed
hypothetical_function()For the full table of chunk options, see the Quick Reference at the end of this chapter.
6.3.6 Documenting Inputs and Outputs
After the setup chunk, add an explicit inputs section that loads all dependencies. This makes it immediately clear what the script needs to run:
#| label: inputs
# --- Inputs (from other scripts) ---
results <- readRDS(here("outs/03_differential/limma_results.rds"))
# --- Inputs (external data) ---
metadata <- read_csv(here("data/sample_metadata.csv"))#| label: inputs
# --- Inputs (from other scripts) ---
results = pd.read_parquet(PROJECT_ROOT / "outs/03_differential/deseq_results.parquet")
# --- Inputs (external data) ---
metadata = pd.read_csv(PROJECT_ROOT / "data/sample_metadata.csv")Separating inputs from analysis code makes dependencies self-documenting—reading the top of any script shows exactly what it depends on. You can also document inputs and outputs in the introduction text:
# Volcano Plots
This script generates volcano plots for the phosphoproteomics time course.
**Inputs:**
- `outs/03_differential/limma_results.rds`
- `data/sample_metadata.csv`
**Outputs:**
- `outs/04_volcano_plots/volcano_*.pdf`
- `outs/04_volcano_plots/significant_hits.csv`See the Project Organization chapter for how this fits into the larger project structure.
6.4 Saving Outputs
Don’t rely on the Plots pane or copy-paste. Save figures and tables to files explicitly:
#| label: fig-volcano
#| fig-cap: "Volcano plot showing differential phosphorylation"
p <- ggplot(results, aes(x = logFC, y = -log10(adj.P.Val))) +
geom_point() +
theme_minimal()
# Display in rendered document
print(p)
# Save to output folder
ggsave(
file.path(dir_out, "volcano_plot.pdf"),
plot = p,
width = 6,
height = 4
)For tables:
write_csv(significant_hits, file.path(dir_out, "significant_hits.csv"))#| label: fig-volcano
#| fig-cap: "Volcano plot showing differential phosphorylation"
fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(results["logFC"], -np.log10(results["adj_pval"]))
ax.set_xlabel("log2 Fold Change")
ax.set_ylabel("-log10 Adjusted P-value")
plt.tight_layout()
# Save to output folder AND display inline
fig.savefig(out_dir / "volcano_plot.pdf", dpi=300, bbox_inches="tight")
fig.savefig(out_dir / "volcano_plot.png", dpi=300, bbox_inches="tight")
plt.show()For tables:
significant_hits.to_csv(out_dir / "significant_hits.csv", index=False)This approach embeds the figure in the rendered HTML, saves a high-quality copy for publication or further use, and makes the output traceable (the file exists in outs/).
6.5 Working Directory and Paths
When Quarto renders a .qmd, the working directory is the folder containing the .qmd file—not the project root. This can cause path confusion.
project/
├── scripts/
│ └── 01_analysis.qmd ← Working directory during render
├── data/
│ └── input.csv
└── outs/
From scripts/01_analysis.qmd, a relative path to the data would be ../data/input.csv. But this breaks if you move the script or run it from a different location.
The here package finds the project root (by looking for .git, .Rproj, etc.) and builds paths from there:
# Always works, regardless of working directory
data <- read_csv(here::here("data", "input.csv"))
# Instead of fragile relative paths
data <- read_csv("../data/input.csv") # Don't do thisPython doesn’t have a direct equivalent of here, so the setup chunk finds the project root via Git:
PROJECT_ROOT = Path(subprocess.check_output(
["git", "rev-parse", "--show-toplevel"]
).decode().strip())
# Always works, regardless of working directory
data = pd.read_csv(PROJECT_ROOT / "data/input.csv")
# Instead of fragile relative paths
data = pd.read_csv("../data/input.csv") # Don't do thisUse project-root-relative paths for all file operations in your scripts. It makes your code portable and reproducible.
6.6 Rendering
6.6.1 From the Terminal
quarto render scripts/01_analysis.qmdPython QMD files require the conda environment to be active when you render. If you haven’t set up conda yet, the Conda chapter walks through installation and environment creation — come back to this section after that.
source ~/miniconda3/etc/profile.d/conda.sh && conda activate my-project && quarto render scripts/02_plots.qmdIf quarto render fails with ModuleNotFoundError, check that your conda environment is active. This is the number one Python QMD gotcha.
To render all .qmd files in a directory:
quarto render scripts/6.6.2 From Positron
Click the Render button in the editor toolbar, or use Cmd+Shift+K (macOS) / Ctrl+Shift+K (Windows).
6.6.3 Preview Mode
For live feedback during development, use preview mode:
quarto preview scripts/01_analysis.qmdThis opens a browser window that automatically refreshes when you save changes. Useful for tuning formatting, but remember that preview still renders in a fresh session—it’s not the same as interactive execution.
6.7 Best Practices
6.7.1 Render Before Committing
Always render the full document before committing to Git. This catches missing packages (installed interactively but not in your lockfile), missing objects (created interactively but not in the script), and order dependencies (chunks that depend on earlier chunks you modified).
6.7.2 Self-Contained Scripts
Every .qmd should run successfully from a fresh R or Python session. Don’t assume objects exist from previous interactive work. If render fails, your script isn’t self-contained.
6.7.3 Clear Section Structure
Organize your script with clear headings:
# Introduction
# Setup
# Load Data
# Analysis
# Results
# SummaryThis makes the script navigable (via Positron’s Outline panel) and the rendered document readable.
6.7.4 Validation Chunks
For complex analyses, add validation chunks that verify data integrity:
#| label: validate-data
#| include: false
# Check required columns exist
required_cols <- c("sample_id", "condition", "value")
missing_cols <- setdiff(required_cols, names(data))
if (length(missing_cols) > 0) {
stop("Missing required columns: ", paste(missing_cols, collapse = ", "))
}
stopifnot("No data loaded" = nrow(data) > 0)These chunks catch problems early and provide clear error messages.
6.7.5 Provenance Chunk
End every script with a chunk that writes BUILD_INFO.txt and prints session information. This records which script, commit, and timestamp produced the outputs—answering “when was this last regenerated?”
#| label: build-info
writeLines(
c(
paste("script:", "01_script_name.qmd"),
paste("commit:", git_hash),
paste("date:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"))
),
file.path(dir_out, "BUILD_INFO.txt")
)
sessionInfo()#| label: build-info
(out_dir / "BUILD_INFO.txt").write_text(
f"script: 01_script_name.qmd\n"
f"commit: {git_hash}\n"
f"date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
)
import session_info
session_info.show()6.8 Common Issues
Claude Code can debug render failures, especially the common case where code works interactively but fails during rendering.
When I run
quarto render analysis.qmd, I get this error: [paste error]. The code runs fine interactively in the console. What’s going wrong?
Claude will trace the error to its cause—typically a missing object that existed in your interactive session but isn’t created in the script, or a path that resolves differently during rendering.
6.8.1 “Object not found” During Render
Code that works interactively may fail during render if you rely on objects not created in the script. You created an object manually in the console, then used it in a chunk without creating it in the script. Ensure all objects are created within the .qmd and render frequently to catch this early.
6.8.2 Figures Not Appearing
If a plot doesn’t show up in the rendered output, add an explicit print():
p <- ggplot(data, aes(x, y)) + geom_point()
print(p) # Required inside loops or complex chunksThe explicit print() is needed when the plot is the result of an assignment or is inside a loop/function.
6.8.3 Package Messages Cluttering Output
Set message: false and warning: false in the YAML execute: block to suppress them globally, or per-chunk for specific chunks.
6.8.4 Output File Is Huge
If your HTML is very large:
- Embedded images: Use
self-contained: falseto keep images in a separate_filesfolder - High resolution: Add
fig-dpi: 150to reduce figure resolution - SVG format: Use
fig-format: pnginstead of SVG for complex plots
6.8.5 Chunk Takes Forever
For long-running chunks during development, consider #| cache: true. This caches the chunk’s results—subsequent renders skip execution if the code hasn’t changed. Use sparingly, as caching can cause subtle bugs if dependencies change.
6.9 Quick Reference
6.9.1 YAML Options
6.9.1.1 Document Metadata
| Option | Purpose | Example |
|---|---|---|
title |
Document title (appears at top) | "My Analysis" |
subtitle |
Secondary title | "Brief description" |
author |
Your name | "Jane Doe" |
date |
Date; use today for automatic |
today |
status |
Script lifecycle stage | development |
jupyter |
Jupyter kernel (Python only) | python3 |
6.9.1.2 Format Options (under format: html:)
| Option | Purpose | Recommended |
|---|---|---|
toc |
Include table of contents | true |
toc-depth |
How many heading levels in TOC | 2 |
number-sections |
Number your headings | true |
code-overflow |
How to handle long code lines | wrap |
code-fold |
Collapse code blocks by default | false |
code-tools |
Add show/hide all code button | true |
highlight-style |
Syntax highlighting theme | github |
theme |
Bootstrap theme for HTML | cosmo |
fontsize |
Base font size | 1rem |
linestretch |
Line spacing multiplier | 1.5 |
self-contained |
Single HTML file | true |
6.9.1.3 Execute Options (under execute:)
| Option | Purpose | Recommended |
|---|---|---|
echo |
Show code in output | true |
message |
Show package messages (R only) | false |
warning |
Show warnings | false |
cache |
Cache chunk results | false |
6.9.2 Chunk Options
| Option | Purpose | Values |
|---|---|---|
label |
Chunk name | Any string |
echo |
Show code | true / false |
eval |
Run code | true / false |
include |
Include in output | true / false |
message |
Show messages | true / false |
warning |
Show warnings | true / false |
error |
Continue on error | true / false |
cache |
Cache results | true / false |
fig-cap |
Figure caption | String |
fig-width |
Width in inches | Number |
fig-height |
Height in inches | Number |
fig-dpi |
Resolution | Number (default 72) |
fig-format |
Output format | png / svg / pdf |
tbl-cap |
Table caption | String |
6.9.3 R vs Python Comparison
| Convention | R | Python |
|---|---|---|
| Project root | here::here() |
PROJECT_ROOT (from git) |
| Read CSV | read_csv(here("data/file.csv")) |
pd.read_csv(PROJECT_ROOT / "data/file.csv") |
| Read TSV | read_tsv(here("data/file.tsv")) |
pd.read_csv(PROJECT_ROOT / "data/file.tsv", sep="\t") |
| Read Parquet | arrow::read_parquet(here(...)) |
pd.read_parquet(PROJECT_ROOT / ...) |
| Save figure | ggsave(file.path(dir_out, "fig.pdf")) |
fig.savefig(out_dir / "fig.pdf") |
| Random seed | set.seed(42) |
random.seed(42) + np.random.seed(42) |
| Session info | sessionInfo() |
session_info.show() |
| Chunk label | {r label-name} or #| label: |
#| label: only |
| Helper loading | source(here("R/helpers.R")) |
sys.path.insert(0, str(PROJECT_ROOT / "python")) |
6.9.4 Quarto Commands
| Command | Purpose |
|---|---|
quarto render file.qmd |
Render to HTML |
quarto render file.qmd --to pdf |
Render to PDF |
quarto preview file.qmd |
Live preview in browser |
quarto render directory/ |
Render all .qmd in directory |
quarto check |
Verify Quarto installation |
6.9.5 Keyboard Shortcuts (Positron)
| Action | macOS | Windows |
|---|---|---|
| Run line/selection | Cmd+Enter | Ctrl+Enter |
| Run chunk | Cmd+Shift+Enter | Ctrl+Shift+Enter |
| Render document | Cmd+Shift+K | Ctrl+Shift+K |
| Insert R chunk | Cmd+Option+I | Ctrl+Alt+I |
For complete, copy-paste-ready templates (YAML headers, setup chunks, provenance chunks for both R and Python), see Appendix C.
6.10 Python-Specific Notes
This section collects the Python-specific details that don’t fit neatly into the tabsets above. If you haven’t set up conda yet, read the Conda chapter first — these notes will make more sense after that.
Conda must be active for rendering. This is the number one Python QMD gotcha. Unlike R (which finds packages via renv automatically), Python QMD files require the conda environment to be active when you render. If quarto render fails with ModuleNotFoundError, activate your environment first.
Install ipykernel. Quarto uses Jupyter kernels to execute Python code. Your conda environment needs ipykernel installed (conda install ipykernel) or rendering will fail.
Install session-info. For the provenance chunk to work, install session-info in your conda environment: pip install session-info. Note the dash in the install name vs. the underscore in the import (import session_info) — this is a common Python convention where package install names use dashes but module names use underscores.
Don’t mix languages. Do not mix R and Python chunks in a single .qmd. Each script uses one language. Scripts communicate through files in outs/, not shared memory. If an R script produces data that a Python script needs, save it as Parquet (see Project Organization).
Selecting the interpreter. Ensure Positron is using the correct conda environment: open the Command Palette (Cmd/Ctrl+Shift+P), type “Python: Select Interpreter”, and choose your project’s environment.