├── .devcontainer └── devcontainer.json ├── .github └── workflows │ └── publish-website.yml ├── .gitignore ├── .quartoignore ├── README.md ├── _extensions └── panelize │ ├── _extension.yml │ └── panelize.lua ├── docs ├── .gitignore ├── _quarto.yml ├── index.qmd ├── qpanelize-cell.qmd ├── qpanelize-install.qmd ├── qpanelize-pyodide.qmd ├── qpanelize-release-notes.qmd ├── qpanelize-webr.qmd └── requirements.txt ├── logo-panelize.png └── panelize.code-workspace /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // Config options: https://github.com/rocker-org/devcontainer-templates/tree/main/src/r-ver 2 | { 3 | "name": "R (rocker/r-ver base)", 4 | "image": "ghcr.io/rocker-org/devcontainer/r-ver:4.4", 5 | // Add software 6 | "features": { 7 | // Required to test with knitr 8 | // R package config: https://github.com/rocker-org/devcontainer-features/blob/main/src/r-rig/README.md 9 | "ghcr.io/rocker-org/devcontainer-features/r-rig:1": { 10 | "version": "none", 11 | "installRMarkdown": true, 12 | "installJupyterlab": true, 13 | "installRadian": true 14 | }, 15 | // You may wish to switch prerelease to latest for stable development 16 | // Quarto configuration : https://github.com/rocker-org/devcontainer-features/blob/main/src/quarto-cli/README.md 17 | "ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": { 18 | "installTinyTex": true, 19 | "version": "prerelease" 20 | } 21 | }, 22 | "customizations": { 23 | "vscode": { 24 | "settings": { 25 | "r.rterm.linux": "/usr/local/bin/radian", 26 | "r.bracketedPaste": true, 27 | "r.plot.useHttpgd": true, 28 | "[r]": { 29 | "editor.wordSeparators": "`~!@#%$^&*()-=+[{]}\\|;:'\",<>/?" 30 | } 31 | }, 32 | // Enable a development set of extensions for Lua and Quarto 33 | "extensions": ["quarto.quarto", "sumneko.lua", "GitHub.copilot"] 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/publish-website.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main, master] 4 | release: 5 | types: [published] 6 | workflow_dispatch: {} 7 | 8 | name: demo-website 9 | 10 | jobs: 11 | demo-website: 12 | runs-on: ubuntu-latest 13 | # Only restrict concurrency for non-PR jobs 14 | concurrency: 15 | group: quarto-publish-${{ github.event_name != 'pull_request' || github.run_id }} 16 | permissions: 17 | contents: write 18 | steps: 19 | - name: "Check out repository" 20 | uses: actions/checkout@v4 21 | 22 | # To render using knitr, we need a few more setup steps... 23 | # If we didn't want the examples to use `engine: knitr`, we could 24 | # skip a few of the setup steps. 25 | - name: "Setup R" 26 | uses: r-lib/actions/setup-r@v2 27 | 28 | - name: "Setup R dependencies for Quarto's knitr engine" 29 | uses: r-lib/actions/setup-r-dependencies@v2 30 | with: 31 | packages: 32 | any::knitr 33 | any::rmarkdown 34 | any::downlit 35 | any::xml2 36 | any::reticulate 37 | 38 | # Setup Python for reticulate 39 | - uses: actions/setup-python@v5 40 | with: 41 | python-version: "3.x" 42 | 43 | # Install python dependencies for reticulate 44 | - name: Setup r-reticulate venv 45 | shell: Rscript {0} 46 | run: | 47 | path_to_python <- reticulate::virtualenv_create( 48 | envname = "r-reticulate", 49 | python = Sys.which("python"), 50 | requirements = "docs/requirements.txt" 51 | ) 52 | writeLines(sprintf("RETICULATE_PYTHON=%s", path_to_python), 53 | Sys.getenv("GITHUB_ENV")) 54 | 55 | 56 | # Back to our regularly scheduled Quarto output 57 | - name: "Set up Quarto" 58 | uses: quarto-dev/quarto-actions/setup@v2 59 | with: 60 | version: "pre-release" 61 | 62 | # Install quarto extensions 63 | - name: "Install quarto extension for quarto-webr and quarto-pyodide" 64 | shell: bash 65 | run: | 66 | cd docs/ 67 | quarto add --no-prompt coatless/quarto-webr 68 | quarto add --no-prompt coatless-quarto/pyodide 69 | cp -r ../_extensions/ _extensions 70 | 71 | - name: Publish to GitHub Pages (and render) 72 | uses: quarto-dev/quarto-actions/publish@v2 73 | with: 74 | target: gh-pages 75 | path: docs -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.luarc.json 2 | docs/_site/* -------------------------------------------------------------------------------- /.quartoignore: -------------------------------------------------------------------------------- 1 | logo-panelize.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # panelize: Tabset Code Cells in Quarto 2 | 3 | The `quarto-panelize` extension allows you to tabbify existing code cells to show their source or add interactivity. 4 | 5 | ## Installation 6 | 7 | To install the `quarto-panelize` extension, follow these steps: 8 | 9 | 1. Enter a Quarto project. 10 | 11 | 2. Open your terminal inside the Quarto project. 12 | 13 | 3. Run the following command: 14 | 15 | ```bash 16 | quarto add coatless-quarto/panelize 17 | ``` 18 | 19 | If you wish to make your code interactive, please install the following Quarto extensions: 20 | 21 | ```sh 22 | # For Python 23 | quarto add coatless-quarto/pyodide 24 | 25 | # For R 26 | quarto add coatless/quarto-webr 27 | ``` 28 | 29 | These commands will download and install the extension as well as any dependencies under the `_extensions` subdirectory of your Quarto project. If you are using version control, ensure that you include this directory in your repository. 30 | 31 | ## Usage 32 | 33 | For each document, place the `panelize` filter in the document's header: 34 | 35 | ```yml 36 | filters: 37 | - panelize 38 | ``` 39 | 40 | Then, wrap existing R or Python code cells using a `Div` and specify the a panelize class. 41 | Supported options include: 42 | 43 | | Class | Description | 44 | |---------------|-------------------------------------------------------------------------------------| 45 | | `.to-source` | Convert a code cell to show rendered output and its source. | 46 | | `.to-pyodide` | Convert code cell from static Python code to interactive Python code using Pyodide. | 47 | | `.to-webr` | Convert code cell from static R code to interactive R code using webR. | 48 | 49 | 50 | ### Display Source 51 | 52 | For example, if we have a code cell with R that we want to show its options, then we use: 53 | 54 | ```` md 55 | :::{.to-source} 56 | ```{r} 57 | #| echo: fenced 58 | #| eval: true 59 | 1 + 1 60 | ``` 61 | ::: 62 | ```` 63 | 64 | This will generate output equivalent to: 65 | 66 | ```` md 67 | :::{.panel-tabset} 68 | ### Results 69 | ```{r} 70 | #| eval: true 71 | 1 + 1 72 | ``` 73 | ### Source 74 | ```{{r}} 75 | #| eval: true 76 | 1 + 1 77 | ``` 78 | ::: 79 | ```` 80 | 81 | ### Interactivity 82 | 83 | For creating a tabset that contains both rendered results and interactive option, modify the document header and place the desired extension filter **after** `panelize`, e.g. 84 | 85 | ```yml 86 | filters: 87 | - panelize 88 | - pyodide 89 | - webr 90 | ``` 91 | 92 | > [!IMPORTANT] 93 | > 94 | > Order matters! Please make sure to place the filters after `panelize`. 95 | > Otherwise, the interactivity filter will *not* detect the code cell! 96 | > 97 | 98 | Next, wrap the existing code cell using a `Div` with a class of either `.to-pyodide` or `.to-webr`. 99 | 100 | For Python, that looks like: 101 | 102 | ````md 103 | :::{.to-pyodide} 104 | ```{python} 105 | 4 + 5 106 | ``` 107 | ::: 108 | ```` 109 | 110 | For R, that looks like: 111 | 112 | ````md 113 | :::{.to-webr} 114 | ```{r} 115 | 1 + 1 116 | ``` 117 | ::: 118 | ```` 119 | 120 | ## Acknowledgements 121 | 122 | Thanks to [@mcanouil](https://github.com/mcanouil) and [@cscheid](https://github.com/cscheid) who provided great insight into approaching this problem by re-orienting it in a way that is more managable. Please see the [full discussion](https://github.com/quarto-dev/quarto-cli/discussions/9646). -------------------------------------------------------------------------------- /_extensions/panelize/_extension.yml: -------------------------------------------------------------------------------- 1 | name: panelize 2 | title: Panelize code cells 3 | author: James Joseph Balamuta 4 | version: 0.0.2-dev.1 5 | quarto-required: ">=1.4.554" 6 | contributes: 7 | filters: 8 | - panelize.lua -------------------------------------------------------------------------------- /_extensions/panelize/panelize.lua: -------------------------------------------------------------------------------- 1 | -- Define helper types for clarity 2 | ---@class Block 3 | ---@field t string The type of the block 4 | ---@field attr table Block attributes 5 | ---@field content? table Block content 6 | ---@field classes table List of classes 7 | ---@field text? string Block text if CodeBlock 8 | 9 | ---@class Cell 10 | ---@field code_blocks Block[] List of code blocks 11 | ---@field outputs Block[] List of output blocks 12 | ---@field language string Programming language 13 | 14 | ---@class DocumentMetadata 15 | ---@field panelize table Configuration options 16 | ---@field handler_added boolean Flag for handler addition 17 | 18 | -- Store metadata at module level 19 | ---@type DocumentMetadata 20 | local document_metadata = { 21 | panelize = {}, 22 | handler_added = false 23 | } 24 | 25 | -- Helper function to detect language from a code block 26 | ---@param block Block The code block to analyze 27 | ---@return string|nil language The detected language 28 | local function detect_language(block) 29 | if block.attr.classes:includes("r") then 30 | return "r" 31 | elseif block.attr.classes:includes("python") then 32 | return "python" 33 | elseif block.text:match("^```{{r") then 34 | return "r" 35 | elseif block.text:match("^```{{python") then 36 | return "python" 37 | end 38 | return nil 39 | end 40 | 41 | -- Helper function to clean code block text 42 | ---@param block Block The code block to clean 43 | ---@param language string The programming language 44 | ---@param remove_fences boolean Whether to remove code fences and options 45 | ---@return string cleaned_text The processed text 46 | local function clean_code_text(block, language, remove_fences) 47 | local text = block.text 48 | if remove_fences then 49 | if text:match("^```{{" .. language .. "}") then 50 | text = text:gsub("```{{" .. language .. "}}\n", ""):gsub("\n```", "") 51 | end 52 | text = text:gsub("#|.-\n", "") 53 | end 54 | return text 55 | end 56 | 57 | -- Helper function to extract cell content 58 | ---@param cell_div Block The cell div block 59 | ---@return Cell cell The processed cell content 60 | local function extract_cell_content(cell_div) 61 | local cell = { 62 | blocks = {}, -- Will store alternating code blocks and their outputs 63 | language = nil 64 | } 65 | 66 | -- Process blocks in sequence 67 | for _, block in ipairs(cell_div.content) do 68 | if block.t == "CodeBlock" and block.classes:includes("cell-code") then 69 | table.insert(cell.blocks, {type = "code", content = block}) 70 | -- Detect language from first code block if not already set 71 | if not cell.language then 72 | cell.language = detect_language(block) 73 | end 74 | elseif block.t == "Div" and ( 75 | block.classes:includes("cell-output") or 76 | block.classes:includes("cell-output-stdout") or 77 | block.classes:includes("cell-output-display") 78 | ) then 79 | table.insert(cell.blocks, {type = "output", content = block}) 80 | end 81 | end 82 | 83 | return cell 84 | end 85 | 86 | -- Helper function to create tab content 87 | ---@param cell Cell The cell content 88 | ---@param tab_type string The type of tab ("result", "source", or "interactive") 89 | ---@return pandoc.List content The tab content 90 | local function create_tab_content(cell, tab_type) 91 | local content = pandoc.List() 92 | 93 | if tab_type == "interactive" then 94 | -- For interactive tab, combine all code blocks into one 95 | local combined_code = table.concat( 96 | pandoc.List(cell.blocks) 97 | :filter(function(block) return block.type == "code" end) 98 | :map(function(block) return clean_code_text(block.content, cell.language, true) end), 99 | "\n" 100 | ) 101 | 102 | -- Create single code block with appropriate classes 103 | local classes = cell.language == "r" and {"{webr-r}", "cell-code"} or {"{pyodide-python}", "cell-code"} 104 | local attr = pandoc.Attr("", classes, {}) 105 | content:insert(pandoc.CodeBlock(combined_code, attr)) 106 | else 107 | -- For result and source tabs, process blocks in sequence 108 | for _, block in ipairs(cell.blocks) do 109 | if block.type == "code" then 110 | if tab_type == "result" then 111 | -- For result tab, clean code but keep language class 112 | local new_attr = block.content.attr:clone() 113 | new_attr.classes = pandoc.List({cell.language}) 114 | local cleaned_text = clean_code_text(block.content, cell.language, true) 115 | content:insert(pandoc.CodeBlock(cleaned_text, new_attr)) 116 | else 117 | -- For source tab, use original code block 118 | content:insert(block.content) 119 | end 120 | else -- output block 121 | content:insert(block.content) 122 | end 123 | end 124 | end 125 | 126 | return content 127 | end 128 | 129 | -- Process metadata 130 | function Meta(meta) 131 | if meta and meta.panelize then 132 | for key, value in pairs(meta.panelize) do 133 | document_metadata.panelize[key] = pandoc.utils.stringify(value) 134 | end 135 | end 136 | return meta 137 | end 138 | 139 | -- Main processing function for divs 140 | function Div(div) 141 | -- Check for required classes 142 | local to_webr = div.classes:includes("to-webr") 143 | local to_pyodide = div.classes:includes("to-pyodide") 144 | local to_source = div.classes:includes("to-source") 145 | 146 | if not (to_source or to_webr or to_pyodide) then 147 | return div 148 | end 149 | 150 | -- Find cell div 151 | local cell_div = nil 152 | for _, block in ipairs(div.content) do 153 | if block.t == "Div" and block.classes:includes("cell") then 154 | cell_div = block 155 | break 156 | end 157 | end 158 | 159 | if not cell_div then 160 | return div 161 | end 162 | 163 | -- Extract cell content 164 | local cell = extract_cell_content(cell_div) 165 | 166 | if not cell.language then 167 | quarto.log.error("Please specify either R or Python code cells inside of the .to-* div.") 168 | return div 169 | end 170 | 171 | -- Create tabs 172 | local tabs = pandoc.List() 173 | 174 | if to_webr or to_pyodide then 175 | -- Interactive environment tabs 176 | tabs:insert(quarto.Tab({ 177 | title = "Result", 178 | content = pandoc.Blocks(create_tab_content(cell, "result")) 179 | })) 180 | tabs:insert(quarto.Tab({ 181 | title = "Interactive", 182 | content = pandoc.Blocks(create_tab_content(cell, "interactive")) 183 | })) 184 | else 185 | -- Source code tabs 186 | tabs:insert(quarto.Tab({ 187 | title = "Result", 188 | content = pandoc.Blocks(create_tab_content(cell, "result")) 189 | })) 190 | tabs:insert(quarto.Tab({ 191 | title = "Source", 192 | content = pandoc.Blocks(create_tab_content(cell, "source")) 193 | })) 194 | end 195 | 196 | -- Return just the tabset, replacing the original div 197 | return quarto.Tabset({ 198 | level = 3, 199 | tabs = tabs, 200 | attr = pandoc.Attr("", {"panel-tabset"}, {}) 201 | }) 202 | end 203 | 204 | -- Return the list of functions to register 205 | return { 206 | {Meta = Meta}, 207 | {Div = Div} 208 | } -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /docs/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | 4 | website: 5 | title: "panelize" 6 | reader-mode: true 7 | repo-url: https://github.com/coatless-quarto/panelize/ 8 | repo-actions: [edit, issue] 9 | sidebar: 10 | style: "floating" 11 | search: true 12 | tools: 13 | - icon: github 14 | href: https://github.com/coatless-quarto/panelize/ 15 | contents: 16 | - text: "Home" 17 | file: index.qmd 18 | - text: "Install" 19 | file: qpanelize-install.qmd 20 | - section: "Panelize Demos" 21 | contents: 22 | - text: "Code Cells" 23 | href: qpanelize-cell.qmd 24 | - text: "Python to Pyodide" 25 | href: qpanelize-pyodide.qmd 26 | - text: "R to webR" 27 | href: qpanelize-webr.qmd 28 | - section: "Support" 29 | contents: 30 | - text: "Submit an issue" 31 | href: https://github.com/coatless-quarto/panelize/issues/new/choose 32 | - section: "Extra" 33 | contents: 34 | - qpanelize-release-notes.qmd 35 | 36 | format: 37 | html: 38 | toc: true 39 | 40 | engine: knitr -------------------------------------------------------------------------------- /docs/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Home" 3 | format: 4 | html: 5 | toc: false 6 | engine: knitr 7 | filters: 8 | - panelize 9 | --- 10 | 11 | The `panelize` extension allows you to tabbify existing code cells. The supported options include: 12 | 13 | | Class | Description | 14 | |---------------|-------------------------------------------------------------------------------------| 15 | | `.to-source` | Convert a code cell to show rendered output and its source. | 16 | | `.to-pyodide` | Convert code cell from static Python code to interactive Python code using Pyodide. | 17 | | `.to-webr` | Convert code cell from static R code to interactive R code using webR. | 18 | 19 | You can wrap existing code cells using a `Div` and specify the class. For example, with Python we would have: 20 | 21 | ```` md 22 | :::{.to-source} 23 | ```{{python}} 24 | #| echo: fenced 25 | #| eval: true 26 | x = [1, 2] 27 | print(x) 28 | ``` 29 | ::: 30 | ```` 31 | 32 | This will generate output equivalent to: 33 | 34 | ````md 35 | :::{.panel-tabset} 36 | ### Results 37 | ```{{python}} 38 | #| echo: fenced 39 | #| eval: true 40 | x = [1, 2] 41 | print(x) 42 | ``` 43 | ### Source 44 | ```{{{python}}} 45 | #| eval: true 46 | x = [1, 2] 47 | print(x) 48 | ``` 49 | ::: 50 | ```` 51 | -------------------------------------------------------------------------------- /docs/qpanelize-cell.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Display Code Cell Source Separately" 3 | format: html 4 | filters: 5 | - panelize 6 | --- 7 | 8 | For example, let's take the following code cell using the [fenced](https://quarto.org/docs/computations/execution-options.html#fenced-echo) output to ensure options are passed forward. 9 | 10 | ````md 11 | ```{{r}} 12 | #| echo: fenced 13 | #| eval: true 14 | 1 + 1 15 | 16 | plot(1:10) 17 | ``` 18 | ```` 19 | 20 | Using the **{quarto-panelize}** extension, you can show the code cell and its output together in one tab, and separately display the source of the code cell with nearly all options (minus `echo`) in another tab tab. Here's how it can be done: 21 | 22 | ````md 23 | :::{.to-source} 24 | ```{{r}} 25 | #| echo: fenced 26 | #| eval: true 27 | 1 + 1 28 | 29 | plot(1:10) 30 | ``` 31 | ::: 32 | ```` 33 | 34 | This will create two tabs: Result and Source. 35 | 36 | :::{.to-source} 37 | 38 | ```{r} 39 | #| echo: fenced 40 | #| eval: true 41 | 1 + 1 42 | 43 | plot(1:10) 44 | ``` 45 | 46 | ::: 47 | 48 | Without setting `echo: fenced`, the Source tab will only display the code without results. 49 | 50 | :::{.to-source} 51 | 52 | 53 | ```{r} 54 | #| eval: true 55 | 1 + 1 56 | 57 | plot(1:10) 58 | ``` 59 | 60 | ::: 61 | 62 | -------------------------------------------------------------------------------- /docs/qpanelize-install.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Install the Extension" 3 | format: html 4 | filters: 5 | - panelize 6 | --- 7 | 8 | To install the `quarto-panelize` extension, follow these steps: 9 | 10 | 1. Enter a Quarto project. 11 | 12 | 2. Open your terminal inside the Quarto project. 13 | 14 | 3. Run the following command: 15 | 16 | ```bash 17 | quarto add coatless-quarto/panelize 18 | ``` 19 | 20 | This command will download and install the extension under the `_extensions` subdirectory of your Quarto project. If you are using version control, ensure that you include this directory in your repository. 21 | 22 | ## Interactivity 23 | 24 | If you wish to use the interactive feature, please make sure to install the following Quarto extensions: 25 | 26 | ### Python 27 | 28 | For interactivity with Python, please type into Terminal: 29 | 30 | ```sh 31 | quarto add coatless-quarto/pyodide 32 | ``` 33 | 34 | Please make sure that `panelize` is placed before `pyodide` in the document header `filters` statement, e.g. 35 | 36 | ```yml 37 | --- 38 | filters: 39 | - panelize 40 | - pyodide 41 | --- 42 | ``` 43 | 44 | ### R 45 | 46 | For interactivity with R, please type into Terminal: 47 | 48 | ```sh 49 | quarto add coatless/quarto-webr 50 | ``` 51 | 52 | Please make sure that `panelize` is placed before `webr` in the document header `filters` statement, e.g. 53 | 54 | ```yml 55 | --- 56 | filters: 57 | - panelize 58 | - webr 59 | --- 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /docs/qpanelize-pyodide.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Python to Interactive Python" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - panelize 7 | - pyodide 8 | --- 9 | 10 | # Overview 11 | 12 | We can use **{quarto-panelize}** to take a usual Python code cell and convert it into an interactive cell powered by [Pyodide](https://pyodide.org/en/stable/). In this guide, we'll walk through the steps! 13 | 14 | ## Code Cell 15 | 16 | For example, let's take the following Python cell: 17 | 18 | ````md 19 | ```{{python}} 20 | x = [1, 2] 21 | print(x) 22 | ``` 23 | ```` 24 | 25 | ## Document Header modification 26 | 27 | Next, in our document header, we need to specify both the `panelize` and `pyodide` filters under the `filters` key, e.g. 28 | 29 | 30 | ````md 31 | --- 32 | title: "My title" 33 | format: html 34 | filters: 35 | - panelize 36 | - pyodide 37 | --- 38 | ```` 39 | 40 | :::{.callout-important} 41 | The order matters! Please make sure `panelize` comes before `pyodide`. Otherwise, the `pyodide` filter will _not_ see the code cell. 42 | ::: 43 | 44 | You will also need to have the `{quarto-pyodide}` extension installed by typing in Terminal: 45 | 46 | ````sh 47 | quarto add coatless-quarto/pyodide 48 | ```` 49 | 50 | ## Wraping the code cell 51 | 52 | Next, we use a special class called `.to-pyodide` inside of a Div denoted by `:::` around a usual R code cell, e.g. 53 | 54 | ````md 55 | :::{.to-pyodide} 56 | ```{{python}} 57 | x = [1, 2] 58 | print(x) 59 | ``` 60 | ::: 61 | ```` 62 | 63 | This allows us to ensure the computational order is maintained when translating from R to a `{quarto-webr}` code cell. 64 | 65 | ## Result 66 | 67 | As a result, we now have access to two tabs: Result and Interactive. 68 | 69 | :::{.to-pyodide} 70 | ```{python} 71 | x = [1, 2] 72 | print(x) 73 | ``` 74 | ::: 75 | 76 | ### Graphs 77 | 78 | We can also use the same approach for plotting graphs, e.g. 79 | 80 | :::{.to-pyodide} 81 | ```{python} 82 | import matplotlib.pyplot as plt 83 | 84 | x = [1, 2, 3, 4, 5] 85 | y = [1, 4, 9, 16, 25] 86 | 87 | plt.plot(x, y) 88 | plt.show() 89 | ``` 90 | ::: 91 | 92 | ### Multiline 93 | 94 | We can also use the same approach for multiline code cells, e.g. 95 | 96 | :::{.to-pyodide} 97 | ```{python} 98 | x = list(range(1, 11)) 99 | x 100 | 101 | y = [i**2 for i in x] 102 | y 103 | 104 | import matplotlib.pyplot as plt 105 | 106 | x = [1, 2, 3, 4, 5] 107 | y = [1, 4, 9, 16, 25] 108 | 109 | plt.plot(x, y) 110 | plt.show() 111 | ``` 112 | ::: 113 | -------------------------------------------------------------------------------- /docs/qpanelize-release-notes.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Release Notes" 3 | date: "05-16-2024" 4 | date-modified: last-modified 5 | engine: markdown 6 | format: 7 | html: 8 | toc: true 9 | --- 10 | 11 | # 0.0.2-dev.1: ???? (??-??-????) 12 | 13 | ## Features 14 | 15 | ## Bug fixes 16 | 17 | 18 | # 0.0.2: Playful Graphs (02-04-2024) 19 | 20 | ## Features 21 | 22 | - Graphs can now be displayed in the `panelize` extension. 23 | 24 | ## Bug fixes 25 | 26 | - Fixed a bug where the `panelize` extension was not allow for multiple outputs to be shown in rendered results and interactive code chunks. 27 | 28 | ## Documentation 29 | 30 | - Added examples for displaying graphs and multiline code cells in the `panelize` extension. 31 | 32 | # 0.0.1: Interactive Polyglot (06-11-2024) 33 | 34 | ## Features 35 | 36 | - `panelize` allows for Quarto code cells to be tabbified. 37 | - `.to-source`: converts an existing code cell also show its source with options. 38 | - `.to-pyodide`: converts a Python cell to Python 39 | - `.to-webr`: converts an R code cell to webR 40 | -------------------------------------------------------------------------------- /docs/qpanelize-webr.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "R to Interactive R" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - panelize 7 | - webr 8 | --- 9 | 10 | # Overview 11 | 12 | We can use **{quarto-panelize}** to take a usual R code cell and convert it into an interactive cell powered by [webR](https://docs.r-wasm.org/). In this guide, we'll walk through the steps! 13 | 14 | ## Code Cell 15 | 16 | For example, let's take the following R cell: 17 | 18 | ````md 19 | ```{{r}} 20 | 1 + 1 21 | ``` 22 | ```` 23 | 24 | ## Document Header modification 25 | 26 | Next, in our document header, we need to specify both the `panelize` and `webr` filters under the `filters` key, e.g. 27 | 28 | 29 | ````md 30 | --- 31 | title: "My title" 32 | format: html 33 | filters: 34 | - panelize 35 | - webr 36 | --- 37 | ```` 38 | 39 | :::{.callout-important} 40 | The order matters! Please make sure `panelize` comes before `webr`. Otherwise, the `webr` filter will _not_ see the code cell. 41 | ::: 42 | 43 | You will also need to have the `{quarto-webr}` extension installed by typing in Terminal: 44 | 45 | ````sh 46 | quarto add coatless/quarto-webr 47 | ```` 48 | 49 | ## Wraping the code cell 50 | 51 | Next, we use a special class called `.to-webr` inside of a Div denoted by `:::` around a usual R code cell, e.g. 52 | 53 | ````md 54 | :::{.to-webr} 55 | ```{{r}} 56 | 1 + 1 57 | ``` 58 | ::: 59 | ```` 60 | 61 | This allows us to ensure the computational order is maintained when translating from R to a `{quarto-webr}` code cell. 62 | 63 | ## Result 64 | 65 | As a result, we now have access to two tabs: Result and Interactive. 66 | 67 | :::{.to-webr} 68 | ```{r} 69 | 1 + 1 70 | ``` 71 | ::: 72 | 73 | The `Result` tab shows the output of the code cell, while the `Interactive` tab allows us to interact with the code cell. 74 | 75 | ### Graphs 76 | 77 | We can also use the same approach for plotting graphs, e.g. 78 | 79 | :::{.to-webr} 80 | ```{r} 81 | plot(1:10) 82 | ``` 83 | ::: 84 | 85 | ### Multiline 86 | 87 | We can also use the same approach for multiline code cells, e.g. 88 | 89 | :::{.to-webr} 90 | ```{r} 91 | x <- 1:10 92 | x 93 | 94 | y <- x^2 95 | y 96 | 97 | plot(x, y) 98 | ``` 99 | ::: 100 | 101 | 102 | ## Autorun Code 103 | 104 | You may wish to allow the interactive cells to be automatically run when the document opens by specifying in the document header: 105 | 106 | ```yml 107 | --- 108 | title: "My title" 109 | format: html 110 | webr: 111 | cell-options: 112 | autorun: true 113 | filters: 114 | - panelize 115 | - webr 116 | --- 117 | ``` -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib 2 | -------------------------------------------------------------------------------- /logo-panelize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coatless-quarto/panelize/788385fc7bc9cb754f2965792190e03d22d1c46b/logo-panelize.png -------------------------------------------------------------------------------- /panelize.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } --------------------------------------------------------------------------------