diff --git a/.Rprofile b/.Rprofile new file mode 100644 index 0000000..81b960f --- /dev/null +++ b/.Rprofile @@ -0,0 +1 @@ +source("renv/activate.R") diff --git a/.gitignore b/.gitignore index d1902b1..9a99413 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,11 @@ rsconnect/** .DS_Store -*.html \ No newline at end of file +*.html + +# posit publisher deployment folder +.posit/ + +# renv +renv/library/ +renv/staging/ diff --git a/README.md b/README.md index 1470f13..b7df928 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,75 @@ # python-training -An interactive, online introduction to python training for employees in Public Health Scotland. +This is an interactive, online introduction to python training for employees +in Public Health Scotland. + +## Running in Posit Workbench + +This project has a renv (R environment) and you can recreate the needed packages following these steps: +1. Install renv in your current R session: +``` r +install.packages("renv") +``` +2. Restart your R session +3. Run this command in R console: +``` r +renv::restore() +``` +4. All the required packages will be installed. +5. If the restore process fails you can install required R packages running these lines of code in your R console: +``` r +install.packages("learnr") +install.packages("reticulate") +``` + +### R required packages + + +| Package | Description | +|---------|---------| +| learnr | It is required to build the shiny app | +| reticulate | It is required for running embedded python sessions | + +### Python required packages + +The required Python are available in requirements.txt file. No need to install since reticulate R package manages the required virtual environment installation. + +| Package | Description | +|---------|---------| +| pandas | It is required to read files (e.g. CSV) and wrangle its content | + + +### Troubleshooting + +- If PWB has been updated it means there are new Python versions. So you have to +check if your previously created pyenv is still there. Run this command in the +terminal tab: `ls -l ~/.virtualenvs` +- If you see pyenv folder, you have to delete it using this command: +`rm -rf ~/.virtualenvs/pyenv` +- The previous pyenv gets obsolete because of a PWB update with new Python +versions. +- We will be able to run this project because it will create a new pyenv +(with the new Python version). + +## Deployment +This project can be deployed in Posit connect using Posit Publisher Positron extension. Go to the following repo [vscode_prep](https://github.com/Public-Health-Scotland/vscode_prep) and go to Deployment folder. This folder contains general steps to deploy a project. + +- You will need an API token to authenticate your permissions (Viewer/Publisher) in Posit Connect +- Ask for the current Posit connect project URL if it has already been deployed. +- Check Folder content table to see which files are required for deployment (if you upload everything you will waste space) + +### Folder content + +This project contains the following folders and files: + +| Folder/File | Description | To deploy | On GitHub | +|--------------|-----------------------------|--------------|--------------| +| data/ | This folder contains all CSV files used in this project | ✅ | ✅ | +| images/ | This folder contains all required images | ✅ | ✅ | +| css/ | This folder contains CSS to style the project | ✅ | ✅ | +| .gitignore | This file contains a list of files/folders which are not uploaded to GitHub | ❌ | ✅ | +| intro.Rmd | This is the entry point file which contains the main R shiny application | ✅ | ✅ | +| README.md | This file contains the project description | ❌ | ✅ | +| requirements.txt | This file is essencial to create your Python virtual environment using Reticulate R package | ✅ | ✅ | +| .Rprofile | R project file generated by R studio | ❌ | ✅ | +| renv/ and renv.lock | R environmet to recreated needed packages | ❌ | ✅ | +| .posit | Temporary folder created when using posit publisher extension for deployment | ❌ | ❌ | diff --git a/css/style.css b/css/style.css index 46a3a89..b965c52 100644 --- a/css/style.css +++ b/css/style.css @@ -1,16 +1,78 @@ @import url("https://fonts.googleapis.com/css?family=Open Sans"); @import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap'); -body, h1, h2, h3, h4, h5, h6, p, button { - font-family: 'Open Sans'; +@media (prefers-color-scheme: dark) { + :root { + --phs-logo: url("../images/phs-logo-white.svg"); + --phs-color-bg: #1a1a2e; + --phs-color-fg: #e8e8e8; + --phs-h: #80BCEA; + --phs-code-bg: #252542; + --phs-btn-primary: #252542; + --phs-btn-success: #252542; + } +} + +@media (prefers-color-scheme: light) { + :root { + --phs-logo: url("../images/phs-logo.svg"); + --phs-color-bg: #ffffff; + --phs-color-fg: #333333; + --phs-h: #433683; + --phs-code-bg: #ffffff; + --phs-btn-primary:#0097d7; + --phs-btn-success: #80ba27; + } +} + +.custom-navbar { + display: flex; + justify-content: flex-end; + align-items: center; + margin-bottom: 10px; +} + +.phs-logo { + background-image: var(--phs-logo); + background-size: contain; + background-repeat: no-repeat; + background-position: right center; + width: 300px; + height: 100px; } -h1, h2 { - color: #433683; +.tutorial-exercise-code-editor { + background-color: var(--phs-code-bg) !important; + color: var(--phs-color-fg); } -h3, h4, h5 { - color: #bd27b9; +pre, code { + background-color: var(--phs-code-bg) !important; + color: var(--phs-color-fg); +} + +.topicsList .topic .nav-link { + color: #808080; + font-weight: bold; +} + +.topicsList .topic.current { + background-color: var(--phs-color-fg); + color: var(--phs-color-bg) !important; +} + +body { + background-color: var(--phs-color-bg); + color: var(--phs-color-fg); +} + +body, h1, h2, h3, h4, h5, h6, p, button { + font-family: 'Open Sans'; +} + +h1, h2, h3, h4, h5 { + color: var(--phs-h); + font-weight: bold; } code { @@ -18,20 +80,42 @@ code { } th { - color: #433683; + color: var(--phs-h); } .panel-heading { - color: #bd27b9; + color: var(--phs-h); padding-bottom: 10px; } .btn-primary { - background-color: #0097d7; + background-color: var(--phs-btn-primary); + color: var(--phs-color-fg); + border-color: var(--phs-color-fg); } .btn-success { - background-color: #80ba27; + background-color: var(--phs-btn-success); + color: var(--phs-color-fg); + border-color: var(--phs-color-fg); +} + +.btn-default { + background-color: var(--phs-btn-success); + color: var(--phs-color-fg); + border-color: var(--phs-color-fg); +} + +.btn-default:hover { + background-color: var(--phs-code-bg); + color: var(--phs-color-fg); + border-color: var(--phs-color-fg); +} + +.btn:hover, .btn:focus, .btn.focus { + background-color: var(--phs-code-bg); + color: var(--phs-color-fg); + border-color: var(--phs-color-fg); } .tidyverse-logo { @@ -56,4 +140,10 @@ img { border-color: #bd27b9; border-radius: 5px; padding: 10px; +} + +.supporting-image-left { + float: left; + width: 400px; + padding-top: 10px; } \ No newline at end of file diff --git a/images/command-mode.PNG b/images/command-mode.png similarity index 100% rename from images/command-mode.PNG rename to images/command-mode.png diff --git a/images/edit-mode.PNG b/images/edit-mode.png similarity index 100% rename from images/edit-mode.PNG rename to images/edit-mode.png diff --git a/images/foundations-buildingblocks.png b/images/foundations-buildingblocks.png new file mode 100644 index 0000000..09f2b9a Binary files /dev/null and b/images/foundations-buildingblocks.png differ diff --git a/images/markdown-example1.PNG b/images/markdown-example1.png similarity index 100% rename from images/markdown-example1.PNG rename to images/markdown-example1.png diff --git a/images/markdown-example2.PNG b/images/markdown-example2.png similarity index 100% rename from images/markdown-example2.PNG rename to images/markdown-example2.png diff --git a/images/markdown-menu.PNG b/images/markdown-menu.png similarity index 100% rename from images/markdown-menu.PNG rename to images/markdown-menu.png diff --git a/images/phs-logo-white.svg b/images/phs-logo-white.svg new file mode 100644 index 0000000..be5760b --- /dev/null +++ b/images/phs-logo-white.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/phs-logo.png b/images/phs-logo.png deleted file mode 100644 index 6ffd92b..0000000 Binary files a/images/phs-logo.png and /dev/null differ diff --git a/images/phs-logo.svg b/images/phs-logo.svg new file mode 100644 index 0000000..8b9161a --- /dev/null +++ b/images/phs-logo.svg @@ -0,0 +1,127 @@ + +image/svg+xml diff --git a/images/python-pwb-blanknb.PNG b/images/python-pwb-blanknb.PNG deleted file mode 100644 index 1a0f29f..0000000 Binary files a/images/python-pwb-blanknb.PNG and /dev/null differ diff --git a/images/python-pwb-blanknb.png b/images/python-pwb-blanknb.png new file mode 100644 index 0000000..cad55e8 Binary files /dev/null and b/images/python-pwb-blanknb.png differ diff --git a/images/python-pwb-newnb.png b/images/python-pwb-newnb.png index af806ec..0fc3a6b 100644 Binary files a/images/python-pwb-newnb.png and b/images/python-pwb-newnb.png differ diff --git a/images/python-pwb-startsession.PNG b/images/python-pwb-startsession.PNG deleted file mode 100644 index 20445a9..0000000 Binary files a/images/python-pwb-startsession.PNG and /dev/null differ diff --git a/images/python-pwb-startsession.png b/images/python-pwb-startsession.png new file mode 100644 index 0000000..402b773 Binary files /dev/null and b/images/python-pwb-startsession.png differ diff --git a/images/python-pwb.png b/images/python-pwb.png index 67b031f..5906c86 100644 Binary files a/images/python-pwb.png and b/images/python-pwb.png differ diff --git a/images/vs-code-file.png b/images/vs-code-file.png new file mode 100755 index 0000000..16c0369 Binary files /dev/null and b/images/vs-code-file.png differ diff --git a/images/vs-code-interactive.png b/images/vs-code-interactive.png new file mode 100755 index 0000000..5060f8a Binary files /dev/null and b/images/vs-code-interactive.png differ diff --git a/images/vs-code-notebook.png b/images/vs-code-notebook.png new file mode 100755 index 0000000..58a502a Binary files /dev/null and b/images/vs-code-notebook.png differ diff --git a/images/vs-code-overview.png b/images/vs-code-overview.png new file mode 100644 index 0000000..a8975f2 Binary files /dev/null and b/images/vs-code-overview.png differ diff --git a/images/vs-code-venv.png b/images/vs-code-venv.png new file mode 100755 index 0000000..84cda6c Binary files /dev/null and b/images/vs-code-venv.png differ diff --git a/images/vs-code.png b/images/vs-code.png new file mode 100755 index 0000000..c6f96f9 Binary files /dev/null and b/images/vs-code.png differ diff --git a/intro.Rmd b/intro.Rmd index 0c6eefc..539b097 100755 --- a/intro.Rmd +++ b/intro.Rmd @@ -15,20 +15,27 @@ runtime: shiny_prerendered # See here for learnr package documentation: https://rstudio.github.io/learnr/ -# Include packages here that are required throughout the training +# Unset forced Python (PWB) if present +if (nzchar(Sys.getenv("RETICULATE_PYTHON"))) { + Sys.unsetenv("RETICULATE_PYTHON") +} -#install.packages("learnr") -library(learnr) # Required to build the Shiny app -#install.packages("gradethis") -library(gradethis) # Required for specific code checking and specific feedback -#install.packages("reticulate") +# Include packages here that are required throughout the training +library(learnr) library(reticulate) +# Clear Prerendered Output +rmarkdown::shiny_prerendered_clean("intro.Rmd") +# Clear Knitr Cache +unlink("intro_cache", recursive = TRUE) + knitr::opts_chunk$set(echo = FALSE) -tutorial_options( - exercise.checker = gradethis::grade_learnr -) +# Create environment only if it doesn’t exist +reticulate::virtualenv_create(envname = "pyenv") +reticulate::virtualenv_install("pyenv", requirements = "requirements.txt") +# Activate pyenv virtual environment +reticulate::use_virtualenv("pyenv", required = TRUE) ``` @@ -38,16 +45,18 @@ import pandas as pd borders = pd.read_csv("data/borders_inc_age.csv") -borders2 = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'HospitalCode', 'Specialty']) +borders_columns = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'HospitalCode', 'Specialty']) ``` -```{r phs-logo, echo=FALSE, fig.align='right', out.width="40%"} -knitr::include_graphics("images/phs-logo.png") -``` +
+ +
## Introduction -Welcome to an introduction to python. This course is designed as a self-led introduction to R Markdown for anyone in Public Health Scotland. +Welcome to an introduction to python. This course is designed as a self-led introduction to python for anyone in Public Health Scotland. It covers fundamental knowledge such as various data types (e.g. numbers, strings and boolean), how to write functions, importing and exporting datasets and data wrangling. You can explore python by going through the course and experimenting coding in the embedded code chunks. + +Here is the short video of a quick introduction to python: ![](https://www.youtube.com/watch?v=xkZMUX_oQX4)

Course Info

@@ -61,36 +70,150 @@ Welcome to an introduction to python. This course is designed as a self-led intr ### What is Python? -Python is a powerful general purpose programming language with widespread use in many application domains. Python is open source and free to use, and available for all major operating systems. +- Python is a powerful general purpose programming language with widespread use +in many application domains. -### How does Python run? +- Python is open source and free to use, and available for all major operating +systems. -Traditionally, when a Python script is run, the entire script is interpreted and run from the top down. +- Supported on PHS Posit Workbench. -```{python runtime, eval = FALSE, echo = TRUE} -a = 15 -b = 10 -c = a + b -print(c) +- Learning Python opens up professional development opportunities. + + +## IDE + +There are several environments where you can run Python code, such as "VS Code", "JupyterLab", "Jupyter Notebook". Here we will give an introduction on VS Code +and Jupyter Notebook. + +### VS Code + +Visual Studio Code is an open-source code editor that supports multiple programming languages including Python and R and is highly customisable with extensions. For the purposes of this course we will focus on Python. + +#### Getting Started + +1. We can access VS Code on [Posit Workbench](https://pwb-prod.publichealthscotland.org/) the same way we access RStudio. +2. After signing in, click on "New Session" and a dialog box will pop up. +3. Click on "VS Code" from the options at the start. +4. Select your memory requirements. +5. Click on "Start Session". + +```{r vscode, fig.align='center', out.width="60%"} +knitr::include_graphics("images/vs-code.png") ``` +
-When the above Python script is run, the entire script will be run from the top down, resulting in an output of `25`. +##### Layout of the Interface -There are a number of advantages to having Python scripts run this way. To name a few: +The layout of the VS Code interface can be divided into 6 different parts: -* The script has a sequential flow -* It is easier to debug -* It is clearer and more readable +1. **Activity Bar**: This is located on the far left side of the interface. This lets you access different options and switch between different views on the primary side bar. -However, there are a number of ways to run individual lines of code within a Python script, should that be preferred. In this course, we will touch upon `Jupyter Notebook` in the *IDE* section, where this can be accomplished. +2. **Primary Side Bar**: This is located on the left side of the interface to the right of the activity bar. It contains different views like the Explorer, Search, and Source Control to assist you while working on your project. +3. **Editor**: This is located in the center of the interface and is the main place to edit your files. You can open as many editors as you like side by side vertically and horizontally. +4. **Panel**: This is located at the bottom of the interface below the editor. This contains output, debug information, errors and warnings, and an integrated terminal. To open the terminal the keyboard shortcut is *Ctrl + '*. -## IDE +5. **Command Palette**: This is located right at the top of the interface. The keyboard shortcut *Ctrl + Shift + P* brings up the Command Palette and provides access to commands. -### Jupyter Notebook +6. **Status Bar**: This is located right at the bottom of the interface and provides information about the open project. + +```{r vscodeoverview, fig.align='center', out.width="100%"} +knitr::include_graphics("images/vs-code-overview.png") +``` + +##### Opening Files and Folders + +Once your session opens you can go ahead and open a folder by either clicking on the folder in the explorer pane and then "Open Folder". You can open a file using the keyboard shortcut *Ctrl + O*. You can create a new file by pressing the "New File" button located to the right of your folder name. + +```{r vscodefile, fig.align='center', out.width="40%"} +knitr::include_graphics("images/vs-code-file.png") +``` + +The file path for your home directory (`~` in R Studio) is `/mnt/homes/your_username/`. The stats drive can be accessed the same as R Studio: `/conf/...`. +
+ +#### Setting Up + +Before you start using VS Code you must set up a few different aspects. This section will cover extensions and environments. Although this section should be sufficient for getting set up, for full detailed instructions please see: [VS Code Setup instructions](https://github.com/Public-Health-Scotland/vscode_prep). These instructions include setting up extensions, creating environments, installing packages, using version control, and other hints and tips. + +##### Extensions + +In order to use VS Code you first need to install extensions. Extensions are essentially add-ons that allow you to customise what VS Code can do. You can install extensions individually however for getting started it is recommended that you do the following: + +1. Clone the following repo that can be found [here](https://github.com/Public-Health-Scotland/vscode_prep). This can be done by entering the following into the terminal `git clone https://github.com/Public-Health-Scotland/vscode_prep.git`. + +2. Once cloned, open this folder. To do this, click the explorer button on the left hand menu and then click on the open folder button. You should then be able to select the "vscode_prep" folder and click "OK". + +3. Within this folder is a script called `install_extensions.sh` which will automate the installation process. It already contains the extensions you will need to get started but it can be modified depending on your needs. To execute this script enter `bash install_extensions.sh vscode base` in the terminal. + +4. You will see *Installation completed!* in your terminal. This means everything has worked and the extensions should have been installed. Go to Extensions icon on Activity Bar and you should see a list of the extensions installed. + + +##### Environments + +You can use venv (similar to renv in R) to create environments (private package container). It is recommended that for each project you have a new environment. You can create venv inside your Python project or outside. + +To create your first venv follow these instructions: + +1. If you cloned vscode_prep, you should close vscode_prep ("File" then "Close Folder") first and start from the main user path. Open the terminal and create a folder for your new project (e.g python_demo). Use the following command in your terminal `mkdir python_demo`. + +2. Open this folder by clicking the explorer button on the left hand menu and then clicking on the open folder button. You should then be able to select the python_demo folder and click ok. + +3. In order to create a venv within this folder enter `python -m venv .venv` into the terminal. This creates a venv using whichever interpreter Python currently points to on your system. If you wish to specify a folder outwith your current folder and want your environment to use a specific Python version use something like: `/opt/python/3.11.13/bin/python3 -m venv your_file_path/.venv`. This uses the Python 3.11.13 interpreter to create a virtual environment at `your_file_path/.venv`. + +4. Once you have created your environment you will need to activate it. If your venv is in your current folder enter the following into the terminal `source .venv/bin/activate`. If your venv is outwith your current folder you will need to specify the file path like the following `source your_file_path/.venv/bin/activate`. + +5. You can refresh your VS Code to make sure your venv has been detected. Press *Ctrl + Shift + P* and search Developer reload window. You should see .venv as part of the terminal line. If venv has not been detect you may need to press *Ctrl + Shift + P*, search "Python: Select Interpreter" and manually select your venv. +```{r vscodevenv, fig.align='center', out.width="100%"} +knitr::include_graphics("images/vs-code-venv.png") +``` + +6. You will need to update your pip (Python package manager) which helps to download new packages: `pip install --upgrade pip wheel`. -There are several environments where you can run Python codes, such as "JupyterLab", "Jupyter Notebook". In this training course, we will use “Jupyter Notebook”. +7. You have 2 options to install required packages (once your Python environment is activated). +* Option 1: Best practice is to have a `requirements.txt` file in every Python project folder. This would contain all the required packages for your project. An example of a `requirements.txt` file can be found in the [VS Code Setup instruction](https://github.com/Public-Health-Scotland/vscode_prep). To execute your file enter the following into the terminal `pip install -r requirements.txt --prefer-binary`. +* Option 2: Installing one package at a time using the command in terminal: `pip install pandas==2.3.3 --prefer-binary`. + +Note: If you don't activate your Python environment you will probably install your package in the main Python installation. + + +#### Running Code + +VS Code provides multiple ways to run code, with different approaches being more suitable depending on your workflow and the type of task you are performing. + +##### Running an Entire Script + +To execute the full script you can type the following into the terminal and press enter. The easiest way to open the terminal is the keyboard shortcut *Ctrl + '*. +```{python terminal, eval = FALSE, echo = TRUE} +python your_file_name.py +``` + +Another way to run the whole script is to use the run Python file button at the top of the editor. This is similar to using source to run a script in RStudio. + +##### Running Code Snippets Interactively + +If you wish to run snippets of your code or run it line by line you can do this using a Python Interactive Window. By pressing *Shift + Enter* on a line of code it should open an interactive window as shown below. You can also highlight sections of code and press *Shift + Enter*. This is very similar to running code in RStudio by pressing *Ctrl + Enter*. + +When you run code interactively you have to make sure the kernel selected in the right hand corner of the interactive pane is the correct venv. + +```{r vscodeinteractive, fig.align='center',out.width="100%"} +knitr::include_graphics("images/vs-code-interactive.png") +``` + +##### Jupyter Notebook in VS Code + +You can also use Jupyter Notebook by creating a .ipynb file. Each cell can be executed individually using *Shift + Enter* or by pressing the run button. This allows you to create code or markdown snippets. A more detailed introduction of Jupyter Notebook is in the next section. + +When using Jupyter notebooks you have to select a kernel in the top right hand corner of your notebook. You should select the venv you have created for your project. + +```{r vscodenotebook, fig.align='center',out.width="100%"} +knitr::include_graphics("images/vs-code-notebook.png") +``` + + +### Jupyter Notebook Jupyter Notebook is designed for the easy integration of text and Python programming. It provides a more interactive workflow for Python programming, analysis and reporting. Some of its key features are: @@ -104,7 +227,7 @@ Jupyter Notebook is designed for the easy integration of text and Python program #### Open a New Jupyter Notebook -We can access "Jupyter Notebook" on [Posit Workbench](https://pwb.publichealthscotland.org/). After signing in, click on New Session and a diaglog box will pop up. Click on Editor and select "Jupyter Notebook" from the drop down list, and then Start Session. +We can access "Jupyter Notebook" on [Posit Workbench](https://pwb-prod.publichealthscotland.org/). After signing in, click on New Session and a diaglog box will pop up. Click on "Jupyter Notebook" and then click "Launch". ```{r openpynb, fig.align='center', out.width="60%"} knitr::include_graphics("images/python-pwb.png") @@ -116,22 +239,23 @@ You will see the interface looks like this. There are three main tabs in Jupyter - **Files** Your file directory - **Running** Lists all of the notebooks currently running -- **Clusters** For using IPython in parallel with your cluster (beyond the scope of this training guidance) ```{r startsession, fig.align='center', out.width="100%"} -knitr::include_graphics("images/python-pwb-startsession.PNG") +knitr::include_graphics("images/python-pwb-startsession.png") ```
-To open a new Jupyter Notebook, click the "New" drop down menu on the Files tab and select “Python 3.10.2” under the notebooks heading. This will open a blank Notebook with an IPython console running underneath it. +To open a new Jupyter Notebook, click the "New" drop down menu on the Files tab and select “Python 3 (ipykernel)” under the notebooks heading. This will open a blank Notebook with an IPython console running underneath it. -```{r newnb, fig.align='center', out.width="100%"} +```{r newnb, fig.align='left', out.width="25%"} knitr::include_graphics("images/python-pwb-newnb.png") ``` +
+ ```{r blanknb, fig.align='center', out.width="100%"} -knitr::include_graphics("images/python-pwb-blanknb.PNG") +knitr::include_graphics("images/python-pwb-blanknb.png") ```
@@ -149,7 +273,7 @@ Jupyter notebook is a modal editor which means that the keyboard does different - **Edit mode** - it is indicated by a green cell border and left sidebar, and a prompt showing in the editor area: ```{r editmode, fig.align='center', out.width="100%"} -knitr::include_graphics("images/edit-mode.PNG") +knitr::include_graphics("images/edit-mode.png") ``` When a cell is in edit mode, you can type things such as Python codes into the cell, like a normal text editor. Enter edit mode by pressing Enter or using the mouse to click on a cell’s editor area. @@ -157,7 +281,7 @@ When a cell is in edit mode, you can type things such as Python codes into the c - **Command mode** - Once you click somewhere else outside the cell or press “esc” on keyboard, the cell turns into Command mode. Command mode is indicated by a grey cell border and a blue sidebar: ```{r commandmode, fig.align='center', out.width="100%"} -knitr::include_graphics("images/command-mode.PNG") +knitr::include_graphics("images/command-mode.png") ``` When you are in command mode, you are able to edit the notebook as a whole, but not type into individual cells. Most importantly, in command mode, the keyboard is mapped to a set of shortcuts that let you perform notebook and cell actions efficiently. For example, if you are in command mode and you press C and V, you will copy and paste the current cell. @@ -169,7 +293,7 @@ A full list of useful shortcuts is available by going to "Help > Keyboard Shortc Markdown text cells support plain text, Markdown and HTML. It will be useful to create headings, text instructions etc using markdown to organise the notebook like a written document. A cell can be changed from code mode to markdown mode by going to the top menu bar "Cell > Cell Type > Markdown". Or select “Markdown” from the dropdown list: ```{r markdown, fig.align='center', out.width="100%"} -knitr::include_graphics("images/markdown-menu.PNG") +knitr::include_graphics("images/markdown-menu.png") ``` Or press M while in Command Mode and highlighting the cell. @@ -177,36 +301,74 @@ Or press M while in Command Mode and highlighting the cell. Here is an example of typing some text in a markdown cell. You can use hash key “#” to indicate the size of heading, followed by a space and the text. ```{r markdown-example1, fig.align='center', out.width="100%"} -knitr::include_graphics("images/markdown-example1.PNG") +knitr::include_graphics("images/markdown-example1.png") ``` Then press *Shift + Enter* to finish. ```{r markdown-example2, fig.align='center', out.width="100%"} -knitr::include_graphics("images/markdown-example2.PNG") +knitr::include_graphics("images/markdown-example2.png") ``` -#### Python Library - -Python library is a collection of functions and methods that allows you to perform lots of actions without writing your own code. For example, “pandas” is a Python library for data manipulation and analysis, which is used a lot in this training guidance. ## Foundations This section will walk you through some of the foundational knowledge of Python, including structure, style, and key data types. +We’re going to start with a high-level overview of programming concepts which will help lay the foundations for building your python skills. We’ll then build on these concepts with the specific syntax in python. This graphic shows the structure of the concepts and how they come together to form a program: + +
+```{r foundations-buildingblocks, echo=FALSE, fig.align='center', out.width="75%"} +knitr::include_graphics("images/foundations-buildingblocks.png") +``` +
+ +1. **Basic data types** - representing fundamental data, like numbers and text. + +2. **Complex data types** - taking basic data types and forming more complex, composite data types, e.g. tables. + +3. **Variables** - named storage to track "objects" across a program. + +4. **Statements** - a complete line of code, made of expressions and operators. + +5. **Control Flow** - branching (if statements) and iteration (loops). + +6. **Functions** - reusable chunks of code that can take inputs and give outputs. + +
+ +### How does Python run? + +Traditionally, when a Python script is run, the entire script is interpreted and run from the top down. + +```{python runtime, eval = FALSE, echo = TRUE} +a = 15 +b = 10 +c = a + b +print(c) +``` + +When the above Python script is run, the entire script will be run from the top down, resulting in an output of `25`. + +There are a number of advantages to having Python scripts run this way. To name a few: + +* The script has a sequential flow +* It is easier to debug +* It is clearer and more readable + +There are also a number of ways to run individual lines of code within a Python script as described in the IDE section. + ### Structure **Indentation** - where indentation in other programming languages are included as a style preference, indentation in Python is extremely important, as it indicates what blocks of code should be run. -Without proper indentations, your code will not run. Try to run the following code with improper indentation: +Without proper indentations, your code will not run. Try to run the following code with improper indentation and see what the syntax error will be shown: ```{python indentation1, exercise = TRUE} if 1 < 10: print("One is less than ten.") ``` -Note the syntax error which was shown: - Now run the code with the proper indentation: ```{python indentation2, exercise = TRUE} @@ -216,19 +378,38 @@ if 1 < 10: Indentation not only affords proper functionality, but it also enhances readability and comprehension for yourself, and future co-developers. -### Style +### Python Variables -**Naming** - variables and filenames should have meaningful names in *`snake_case`* format, preferring all lower case. +Variables are containers for storing data values. A variable is created the moment you first assign a value to it using `=`. -
-```{r echo=FALSE, fig.align='center', out.width="100%"} -knitr::include_graphics("images/r_coding_cases.png") +```{python assignvariable, exercise=TRUE} +x = 5 +y = "John" +print(x) +print(y) ``` -
-### Numbers +A variable can have a short name (like x and y) or a more descriptive name (age, carname, total_volume). + +Rules for Python variables: + +- A variable name must start with a letter or the underscore character +- A variable name cannot start with a number +- A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ ) +- Variable names are case-sensitive (age, Age and AGE are three different variables) +- A variable name cannot be any of the Python keywords. + +### Basic Data Types + +#### Numbers + +There are 3 main types of numbers that can be declared in Python. + +1. **Integer** - Whole numbers, positive or negative, without a fractional part. They have unlimited precision in Python 3. -There are 3 main types of numbers that can be declared in Python. +2. **Floating point** - Real numbers with a fractional part, denoted by a decimal point or scientific notation. + +3. **Complex** - Numbers with a real and an imaginary component, written as `a + bj`, where `a` is the real part and `b` is the imaginary part. ```{python numbers, eval = FALSE, echo = TRUE} age = 27 # Integers @@ -237,27 +418,44 @@ k = 6.626e-32 # Using scientific notation var1 = 2 + 5.2j # Complex numbers ``` -### Arithmetic Operators +#### Arithmetic Operators The following are examples of all the arithmetic operators available in Python. ```{r, echo = FALSE} operators_table <- data.frame( - "Precedence" = c(1, 2, 3, 4), - "Operator" = c("`+` `-`", "`*` `**` `/`", "`//`", "`%`"), - "Description" = c("Addition, Subtraction", "Multiplication, Power, Division", "Floor Division (round down after division)", "Modulus (remainder after division)") + "Operator" = c("`**`", + "`%`", + "`*` `/`", + "`//`", + "`+` `-`", + "`>` `<` `==` `!= or ~=` `<=` `>=`", + "`! or ~`", + "`&`", + "|"), + "Description" = c("Power", + "Modulus (remainder after division)", + "Multiplication, Division", + "Floor Division (round down after division)", + "Addition, Subtraction", + "Comparison Operators (Greater than, Less than, Equal to, Not Equal to, Less than or equal to, Greater than or equal to)", + "Logical NOT", + "Logical AND", + "Logical OR") ) knitr::kable(operators_table) ``` -### Strings +#### Strings + +Strings in Python are arrays of unicode characters. However, Python does not have a character data type, a single character is simply a string with a length of 1. Strings can be declared with either single or double quotes, and square brackets `[]` can be used to access elements of the string. -Strings in Python are an ordered sequence of characters, and can be declared with either single or double quotes. +```{python strings1, exercise = TRUE} +a = "Hello, World!" -```{python strings1, eval = FALSE, echo = TRUE} -name = 'John' -surname = 'Doe' +# Get the character at position 1 (the first character has the position 0) +print(a[1]) ``` Multiline strings can be declared with triple single and triple double quotes, but note that whitespace characters are recorded in the string e.g. for tabs and for newlines. @@ -273,6 +471,10 @@ multiline The `print()` function interprets these escape characters as expected. ```{python strings3, exercise = TRUE} +multiline = '''White space is +preserved +in multiline strings.''' + print(multiline) ``` @@ -284,7 +486,7 @@ nested_quotes print(nested_quotes) ``` -For strings, the plus `+` sign will concatenate two strings into one, and the asterisk `*` will repeat a string a set number of times. Have a look and click 'Run Code' below to see the output. +For strings, the plus `+` sign will concatenate two strings into one, and the asterisk `*` will repeat a string a set number of times. ```{python string5, exercise = TRUE} print('Hello' + ' ' + 'World') @@ -292,7 +494,28 @@ print('Hello' + ' ' + 'World' * 4) print('Hello' + (' ' + 'World') * 4) ``` -### Boolean +
+ +Python has a set of built-in methods that you can use on strings, such as: + +```{r echo = FALSE} +string_method <- data.frame("Method" = c("capitalize()", "casefold()", "count()"), + "Description" = c("Converts the first character to upper case", + "Converts string into lower case", + "Returns the number of times a specified value occurs in a string")) + +knitr::kable(string_method) +``` + +```{python string6, exercise = TRUE} +txt = "i love apples, apple ARE my favorite fruit" + +txt.capitalize() +txt.casefold() +txt.count("apple") +``` + +#### Boolean Booleans represent either `True` or `False`. @@ -309,13 +532,16 @@ If a value has some sort of content, it is normally evaluated as true: ```{python boolean2, exercise = TRUE} bool("Hi") bool([]) +bool(0) +bool("") +bool(None) ``` -Note that the empty `list` in the second expression returned `False`. +Note that the empty `list`, `0`, `""`, and `None` all returned `False` as they don't have any content. -### Data Types and Type Conversion +#### Data Types and Type Conversion -The `type()` function can be used to query the type of a Python object, and any type conversion can be performed by using the appropriate function e.g. `int()` for integer, `str()` for string, and `float()` for a floating point number. +Dynamic typing is one of Python's core features that sets it apart from statically typed languages. In Python, variables are not bound to a specific type at declaration. Instead, the type is determined at runtime based on the assigned value. This means that a single variable can hold data of different types throughout its lifetime hence making Python a flexible and easy-to-use language for rapid development and prototyping. The `type()` function can be used to query the type of a Python object, and any type conversion can be performed by using the appropriate function e.g. `int()` for integer, `str()` for string, and `float()` for a floating point number. ```{python type-conversion, exercise = TRUE} myint = 12345 @@ -328,10 +554,15 @@ mystr myfloat ``` + ## Data Structures There are various data structures which are built into Python. Some of the main ones are: +- **Sequence Types:** list, tuple, range +- **Mapping Type:** dict +- **Set Types:** set, frozenset + #### Lists - Lists are ordered collections of items. @@ -386,221 +617,301 @@ my_set = {1, 2, 3, 4, 5} print(my_set) ``` -#### Strings -- Strings are sequences of characters. -- They are immutable, meaning you cannot change the characters in a string once it's created. -- Strings support various operations and methods for text manipulation. +## Control Flow & Iteration + +As is the case in most other programming languages, control flow is where decisions are made, and iteration is where processes are repeated. + +### Control Flow - If + +`if` is the most common comparison operator used in Python. + +```{python if1, exercise=TRUE} +a = 5 +b = 100 +if a == 5: + print("a is equal to 5") -```{python stringexample, exercise = TRUE} -my_string = 'Hello, World!' -print(my_string) +if b > a: + print("b is greater than a") ``` -## Functions +There are some further statements when using `if` that you should be familiar with: -In Python, functions are a block of organised and reusable code which performs a specific task. +- `elif` is short for *else if*. `elif` keyword is Python's way of saying "if the previous conditions were not true, then try this condition". It allows you to check multiple expressions for `True` and execute a block of code as soon as one of the conditions evaluates to `True`. -Functions can be called from anywhere within the script, and can be stored anywhere within the script - **however**, it is custom convention to store functions are the top, or near the top, of the script in order to enhance readability and maintenance of the code. +- `else` keyword catches anything which isn't caught by the preceding conditions. It is executed if the preceding `if` and `elif` statements are evaluated to `False`. -### Structure +```{python if2, exercise=TRUE} +a = 100 +b = 35 -Functions are made up of the: +if b > a: + print("b is greater than a") +elif a == b: + print("a and b are equal") +else: + print("a is greater than b") +``` -* Defined keyword `def` -* Function name -* `()` parentheses which may include parameters. -* Function body +If you have only one statement to execute, you can put it on the same line as the `if` statement. +```{python if3, exercise=TRUE} +a = 8 +b = 3 +if a > b: print("a is greater than b") +``` -```{python function1, eval = FALSE, echo = TRUE} -def (): - function_body +### While Loop +With the `while` loop we can execute a set of statements as long as a condition is true. +```{python whileloop1, exercise=TRUE} +i = 1 # define an indexing variable and set to initial value as 1 +while i < 6: + print(i) + i += 1 ``` -Example: +#### The break() Statement +With the `break` statement we can stop the loop even if the while condition is true: -```{python function2, exercise=TRUE} -def greet(): - print("Hello!") +```{python whileloop2, exercise=TRUE} +i = 1 +while i < 6: + print(i) + if i == 3: + break + i += 1 ``` -When you run the above code, you will see that nothing is outputted - this is because the function has not been called. +#### The continue() Statement +With the `continue` statement we can stop the current iteration, and continue with the next: -```{python function3, exercise=TRUE} -def greet(): - print("Hello!") +```{python whileloop3, exercise=TRUE} +i = 0 +while i < 6: + i += 1 + if i == 3: + continue + print(i) +``` -greet() +#### The else() Statement + +With the `else` statement we can run a block of code once when the condition no longer is true: + +```{python whileloop4, exercise=TRUE} +i = 1 +while i < 6: + print(i) + i += 1 +else: + print("i is no longer less than 6") ``` -### Parameters and Arguments +### For Loop -Parameters are variables which are listed inside the parentheses in the function definition. +For loops are used for iteration over a sequence (that is either a list, a tuple, a dictionary, a set, or a string). -They are placeholders are actual values which will be passed into the function when it is called. +There are multiple ways to use `for` loops. -The values passed into a function are called arguments. +#### Iterating Over a List: +```{python forloop1, exercise=TRUE} +list_of_fruits = ["apple", "banana", "cherry"] -```{python function4, exercise=TRUE} -def greet(name): - print("Hello, " + name + "!") - -greet("Bob") +for fruits in list_of_fruits: + print(fruits) ``` -You can also pass through multiple arguments: +#### Using Enumerate: +You can also use `enumerate` to iterate over a sequence and get the index position of each item: -```{python function5, exercise=TRUE} -def add(a,b,c): - print(a + b + c) - -result = add(1,2,3) +```{python forloop2, exercise=TRUE} +list_of_fruits = ["apple", "banana", "cherry"] + +for index, fruits in enumerate(list_of_fruits): + print(index, fruits) ``` -### Return +#### Iterating Over a String: -The return statement can optionally be used to return the data back to the caller. +Iterating over a string with `print()` can print each character in the string in order: -```{python function6, exercise=TRUE} -def add(a,b,c): - return a + b + c - -result = add(1,2,3) -print(result) +```{python forloop3, exercise=TRUE} +for char in "Python": + print(char) ``` +#### Iterating Over a Range: -## Control Flow & Iteration{#comparisonoperators} +To loop through a set of code a specified number of times, we can use the `range()` function, -As is the case in most other programming languages, control flow is where decisions are made, and iteration is where processes are repeated. +The `range()` function returns a sequence of numbers, starting from index 0 by default, and increments by 1 (by default), and ends at a specified number. -### Comparison Operators +Note that `range(6)` is not the values of 0 to 6, but the values 0 to 5. -Here are the most commonly used comparison operators used in conditional statements in Python: +```{python forloop4, exercise=TRUE} +for i in range(6): + print(i) +``` -```{r, echo = FALSE} -operators_table <- data.frame( - "Operator" = c("`>` `<`", "`==` `!=`", "`<=` `>=`","`and` `or`"), - "Description" = c("Greater than, Less than", "Equal to, Not Equal to", "Less than or equal to, Greater than or equal to", "And, Or") -) +The `range()` function defaults to 0 as a starting value, however it is possible to specify the starting value by adding a parameter: `range(2, 6)`, which means values from 2 to 6 (but not including 6): -knitr::kable(operators_table) +```{python forloop5, exercise=TRUE} +for i in range(2, 6): + print(i) ``` +The `range()` function defaults to increment the sequence by 1, however it is possible to specify the increment value by adding a third parameter: `range(2, 30, 3)`: -### Control Flow - If +```{python forloop6, exercise=TRUE} +for i in range(2, 30, 3): + print(i) +``` -`if` is the most common comparison operator used in Python. +#### The break() Statement -```{python if1, exercise=TRUE} -if 5 == 5: - print("5 is equal to 5") +With the `break` statement we can stop the loop before it has looped through all the items: -if 5 == 4 or 5 == 5: - print("Either 5 is equal to 4, or 5 is equal to 5") +Exit the loop when x is "banana": -if 6 <= 6: - print("6 is less than or equal to 6") +```{python break1, exercise=TRUE} +fruits = ["apple", "banana", "cherry"] +for x in fruits: + print(x) + if x == "banana": + break ``` -There are some further statements when using `if` that you should be familiar with: +Exit the loop when x is "banana", but this time the break comes before the print: -- `elif` is short for *else if* and is used for multiple `if` conditions -- `else` is executed if the preceding `if` and `elif` statements are false +```{python break2, exercise=TRUE} +fruits = ["apple", "banana", "cherry"] +for x in fruits: + if x == "banana": + break + print(x) +``` +It would not print "banana" as the loop has already been exit when x equals to "banana". -```{python if2, exercise=TRUE} -def check_if_number_is_1_2_or_3(number): - if number == 1: - print("The number is 1") - elif number == 2: - print("The number is 2") - else: - print("The number is 3") +#### The continue() Statement + +With the `continue` statement we can stop the current iteration of the loop, and continue with the next: -check_if_number_is_1_2_or_3(3) +```{python continue, exercise=TRUE} +fruits = ["apple", "banana", "cherry"] +for x in fruits: + if x == "banana": + continue + print(x) ``` -### For loop +It would not print "banana" as the loop was stopped when x equals to "banana", and then continue with the next one "cherry". -For loops are used for iteration. +#### Nested Loops -There are multiple ways to use for loops. +```{python forloop7, exercise=TRUE} +adjective = ["small", "big", "tasty"] +fruits = ["apple", "banana", "cherry"] -#### Iterating over a list: +for x in adjective: + for y in fruits: + print(x, y) +``` -```{python forloop1, exercise=TRUE} -list_of_fruits = ["apple","banana","cherry"] +## Functions & Libraries -for fruits in list_of_fruits: - print(fruits) -``` +In Python, functions are a block of organised and reusable code which performs a specific task. -#### Using Enumerate: +Functions can be called from anywhere within the script, and can be stored anywhere within the script - **however**, it is custom convention to store functions at the top, or near the top, of the script in order to enhance readability and maintenance of the code. -You can also use `enumerate` to iterate over a sequence and get the index position of each item also: +### Structure -```{python forloop2, exercise=TRUE} -list_of_fruits = ["apple","banana","cherry"] +Functions are made up of the: -for index, fruits in enumerate(list_of_fruits): - print(index,fruits) +* Defined keyword `def` +* Function name +* `()` parentheses which may include parameters. +* Function body + +```{python function1, eval = FALSE, echo = TRUE} +def function_name(): + function_body ``` +Example: -#### Iterating over a string: +```{python function2, exercise=TRUE} +def greet(): + print("Hello!") +``` +When you run the above code, you will see that nothing is output - this is because the function has not been called. -```{python forloop3, exercise=TRUE} -for char in "Python": - print(char) +```{python function3, exercise=TRUE} +def greet(): + print("Hello!") + +greet() ``` -#### Iterating over a range: +### Parameters and Arguments -`range` in Python determines the position of the value, rather than the value itself. +Parameters are variables which are listed inside the parentheses in the function definition. They are placeholders for actual values which will be passed into the function when it is called. -Remember that positions in Python begin at position `0`. +The values passed into a function are called arguments. -```{python forloop4, exercise=TRUE} +```{python function4, exercise=TRUE} +def greet(name): # set the parameter as name + print("Hello, " + name + "!") + +greet("Bob") # argument as Bob +``` -for i in range(5): - print(i) +You can also pass through multiple arguments: +```{python function5, exercise=TRUE} +def add(a, b, c): + print(a + b + c) + +result = add(1, 2, 3) ``` -#### Nested Loops +### Return -```{python forloop5, exercise=TRUE} +The return statement can optionally be used to return the data back to the caller. -adjective = ["red", "big", "tasty"] -fruits = ["apple", "banana", "cherry"] +```{python function6, exercise=TRUE} +def add(a, b, c): + return a + b + c + +result = add(1, 2, 3) +print(result) +``` -for x in adjective: - for y in fruits: - print(x, y) +### Python Library -``` +Python library is a collection of functions and methods that allows you to perform lots of actions without writing your own code. For example, “pandas” is a Python library for data manipulation and analysis, which is used a lot in this training guidance. -## Importing and Exporting Datasets +## File Handling The Python language can be used for data analysis. The first step in performing analysis is to access your dataframe (i.e. your dataset). This section will introduce you how to import and export datasets. -### Read and Save .csv Files +### Read and Save .csv/.xlsx Files -Various commonly used file formats can be read using Python, such as .csv and .xls files. You can import these files by using the “pandas” library. The general code is +Various commonly used file formats can be read using Python, such as .csv and .xlsx files. You can import these files by using the “pandas” library. The general code is -```{python csv-read, eval = FALSE, echo = TRUE} -dataset_name = pd.read_csv("filename.csv") +```{python file-read, eval = FALSE, echo = TRUE} +dataset_name = pd.read_csv("filepath/filename.csv") +dataset_name = pd.read_excel("filepath/filename.xlsx") ``` There are three pieces to this code: @@ -626,73 +937,78 @@ Have a look and click 'Run Code' below to see the output. ```{python csv-read-example, exercise = TRUE} # Import pandas library -import pandas as pd +import pandas as pd + # Read in the dataset -borders = pd.read_csv("data/borders_inc_age.csv") +borders = pd.read_csv("data/borders_inc_age.csv") + # Check the first few rows of the dataset. Default is 5 rows. borders.head() ``` If you make any changes to borders and would like to save it as a new .csv file, use the following command: -```{python csv-save, eval = FALSE, echo = TRUE} -borders.to_csv("file path and name") +```{python file-save, eval = FALSE, echo = TRUE} +borders.to_csv("filepath/filename.csv") +borders.to_excel("filepath/filename.xlsx") ``` -### Read Specific Columns +### Read Web Files -It is possible to omit certain columns from a dataframe when importing a file by using **usecols** command: +The libraries/functions used will vary depending on the structure of the data hosted on the web. This example uses a CSV hosted on [Open Data Platform](https://www.opendata.nhs.scot/) so the process in very similar to before. -```{python csv-read-columns1, exercise = TRUE, exercise.setup = "pandas-setup"} -# Read in the dataset with specific columns -borders2 = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'HospitalCode', 'Specialty']) +```{python web-read-example, exercise = TRUE} +# Import pandas library +import pandas as pd + +# Read in the dataset +hosp = pd.read_csv("https://www.opendata.nhs.scot/dataset/cbd1802e-0e04-4282-88eb-d7bdcfb120f0/resource/c698f450-eeed-41a0-88f7-c1e40a568acc/download/current_nhs_hospitals_in_scotland_010720.csv") # Check the first few rows of the dataset. Default is 5 rows. -borders2.head() +hosp.head() ``` -It is also possible to rearrange the columns within an imported dataframe. The columns in the example above can be rearranged using the following code: +### Read Databases (SMRA) -```{python csv-read-columns2, exercise = TRUE, exercise.setup = "pandas-setup"} -# Rearrange the columns -borders3 = borders2[['URI', 'Specialty', 'HospitalCode']] +There is a guidance on how to retrieve data from SMRA [here](https://github.com/Public-Health-Scotland/python_demo_databases) if you +clone the repository and follow the steps in README. -# Check the first few rows of the dataset. Default is 5 rows. -borders3.head() -``` +The main code to get SMRA data are as follows: -Once the dataframe has been read in, you can delete a specific column (or columns) that you do not need using **del** command: +```{python smra_read, eval = FALSE, echo = TRUE} +# import class from python script +from my_db import MyOracleDB -```{python delete-column, exercise = TRUE, exercise.setup = "pandas-setup"} -# Delete URI column -del borders2["URI"] - -# Check the first few rows of the dataset. Default is 5 rows. -borders2.head() +# create an object +my_oracle_object = MyOracleDB() +# open a connection +my_oracle_object.connect() +# print a retrieved datafraame +print(my_oracle_object.query_to_df("your sql query")) +# close connection +my_oracle_object.close() ``` -### Knowledge Check +### Read Specific Columns -```{r example-quiz} -quiz( - question("[Question]", - answer("[Incorrect answer]", correct = FALSE), - answer("[Incorrect answer with feedback]", correct = FALSE, message = "[Specific feedback.]"), - answer("[Correct answer]", correct = TRUE), - incorrect = "[General feedback for any incorrect answer.]", - allow_retry = TRUE, - random_answer_order = TRUE - ) -) +It is possible to omit certain columns from a dataframe when importing a file by passing a list of columns to **usecols**: + +```{python csv-read-columns1, exercise = TRUE, exercise.setup = "pandas-setup"} +# Read in the dataset with specific columns +borders_columns = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'HospitalCode', 'Specialty']) + +# Check the first few rows of the dataset. Default is 5 rows. +borders_columns.head() ``` -### Code Exercise +It is also possible to rearrange the columns within an imported dataframe. The columns in the example above can be rearranged using the following code: -```{r example-code-q, exercise=TRUE} -# Hello World example -hello_world <- "Hello World" +```{python csv-read-columns2, exercise = TRUE, exercise.setup = "pandas-setup"} +# Rearrange the columns by supplying multiple column names in a list using the inner square brackets. +borders_rearrange = borders_columns[['URI', 'Specialty', 'HospitalCode']] -print(hello_world) +# Check the first few rows of the dataset. Default is 5 rows. +borders_rearrange.head() ``` @@ -700,117 +1016,46 @@ print(hello_world) ### Mean/Median & Summary -* `mean()` and `median()` are passed arrays of values (usually from a data frame) to return the mean and median value. +* `mean()` and `median()` are passed arrays of values (usually from a dataframe) to return the mean and median value. * `describe()` returns all summary statistics based on a given array. -For example, `[""].median()` will generate the `median` value of the values within the stated column. +For example, `df["column_name"].median()` will generate the `median` value of the values within the stated column. -In the exercise below, you have the borders data-set loaded as `borders_data`. See if you can get the mean value for `LengthOfStay`, store it in a variable, and print that variable. Use the hint button if you need some help. +In the example below, we would like to get the mean value for `LengthOfStay` from `borders`: ```{python mean, exercise = TRUE, exercise.setup = "pandas-setup"} +mean_value = borders["LengthOfStay"].mean() # Store the value in a variable -borders_data = pd.read_csv("data/borders_inc_age.csv") - -borders_data -``` - -```{python mean-hint-1} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -borders_data["LengthOfStay"] +print(mean_value) # Print out to see the result ``` - -```{python mean-hint-2} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -borders_data["LengthOfStay"].mean() -``` - - -```{python mean-hint-3} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -mean_value = borders_data["LengthOfStay"].mean() - -print(mean_value) -``` - -```{python mean-solution} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -mean_value = borders_data["LengthOfStay"].mean() - -print(mean_value) -``` - -```{python mean-check} -grade_code() -``` - - ### Frequencies & Crosstabs -* Frequency: `["").value_counts()]` -* Crosstab: `pd.crosstab([""], [""])` -* Crosstab & Add Col/Row Totals: `pd.crosstab([""], [""], margins = True)` -tab - -Create a crosstab for `HospitalCode` and `Sex`, add column and row totals, store the table in a variable, and print it out. Use the hint button if you need some help. - -```{python freq, exercise = TRUE, exercise.setup = "pandas-setup"} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - - +* Frequency: +```{python frequency, eval = FALSE, echo = TRUE} +df["column_name".value_counts()] ``` -```{python freq-hint-1} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -...pd.crosstab(...) +* Crosstab: +```{python crosstab, eval = FALSE, echo = TRUE} +pd.crosstab(df["column_nameA"], df["column_nameB"]) ``` -```{python freq-hint-2} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -crosstab_hospitalcode_sex = pd.crosstab( - borders_data["HospitalCode"], borders_data["Sex"]...) -``` - -```{python freq-hint-3} - -borders_data = pd.read_csv("data/borders_inc_age.csv") - -crosstab_hospitalcode_sex = pd.crosstab( - borders_data["HospitalCode"], borders_data["Sex"], margins = True) -print(crosstab_hospitalcode_sex) +* Crosstab & Add Column/Row Totals: +```{python crosstab2, eval = FALSE, echo = TRUE} +pd.crosstab(df["column_nameA"], df["column_nameB"], margins = True) ``` -```{python freq-solution} - -borders_data = pd.read_csv("data/borders_inc_age.csv") +We would like to create a crosstab for `HospitalCode` and `Sex`, add column and row totals: -crosstab_hospitalcode_sex = pd.crosstab( - borders_data["HospitalCode"], borders_data["Sex"], margins = True) - -print(crosstab_hospitalcode_sex) -``` - -```{python freq-check} -grade_code() +```{python freq, exercise = TRUE, exercise.setup = "pandas-setup"} +pd.crosstab(borders["HospitalCode"], borders["Sex"], margins = True) ``` ## Wrangle – Part 1 -For the next sections, we will focus on using the pandas module manipulate data and data frames. +For the next sections, we will focus on using the pandas module to manipulate data and dataframes. ### Row Indexes @@ -842,68 +1087,88 @@ In this RangeIndex, we start labelling rows at 0, stop before 3, and increase by ### Sorting Rows -The syntax to sort a DataFrame `df` in pandas by a particular column is +You can order the DataFrame rows in ascending order by a particular column. The syntax in pandas is: ```{python sort-value, eval = FALSE, echo = TRUE} df = df.sort_values( - by = 'Column' + by = 'column_name' ) ``` where - `.sort_values()` is a DataFrame method. By default it will sort in ascending order. To sort in descending order you can add `ascending = False`: + ```{python sort-value-desc, eval = FALSE, echo = TRUE} df = df.sort_values( - by = 'Column', + by = 'column_name', ascending = False ) ``` - `by` is a keyword that receives the label of the column to sort by. -Let's sort `borders` by `HospitalCode`: +There is another argument called `inplace` with default value as `False`. It +determines if the sorted value is saved in the output when there is no assignment. +It will save the sorted value if `inplace = True`, or the output is assigned to an object. + +Let's sort `borders` by `HospitalCode`. If `inplace` is set as its default `False` and there is no assignment of the output into an object, the sorted data would +not be saved. ```{python sort-value2, exercise = TRUE, exercise.setup = "pandas-setup"} +# The output would not be saved. borders.sort_values( by = 'HospitalCode' ) + +print(borders) +``` + +```{python sort-value3, exercise = TRUE, exercise.setup = "pandas-setup"} +# The output would be saved. +borders.sort_values( + by = 'HospitalCode', + inplace = True +) + +print(borders) +``` + +```{python sort-value4, exercise = TRUE, exercise.setup = "pandas-setup"} +# The output would be saved if assigning the output to another object. +borders1 = borders.sort_values( + by = 'HospitalCode' +) + +print(borders1, borders) ``` ### Selecting Specific Rows -Sometimes, we are only interested in looking at certain rows and columns of a DataFrame. We can select sections of a DataFrame using two methods: `.loc[]` and `.iloc[]`. +Sometimes, we are only interested in looking at certain rows and columns of a DataFrame. We can select sections of a DataFrame using `.loc[]`. + +The `.loc[]` index works using the index labels: + +```{python loc, eval = FALSE, echo = TRUE} +df.loc[list_of_row_labels, list_of_column_labels] +``` We will explore how both of these work using a mini-DataFrame from `borders` data. ```{python mini-df, echo = FALSE} -import pandas as pd - mini_df = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'Main_Condition']).head(4) mini_df ``` -Before demonstrating we will sort the data by `Main_Condition`. This isn't necessary to use `.loc[]` or `.iloc[]`, but it will make the difference between them clearer. +Before demonstrating we will sort the data by `Main_Condition`. This isn't necessary to use `.loc[]`, but it will show how `.loc[]` works clearer. ```{python mini-df-sort, echo = FALSE} -import pandas as pd - mini_df = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'Main_Condition']).head(4) mini_df.sort_values(by = 'Main_Condition') ``` -Note that the row index is now out-of-order. This will be important later on. - -#### Using `.loc[]` - -The `.loc[]` index works using the index labels: - -```{python loc, eval = FALSE, echo = TRUE} -df.loc[list_of_row_labels, list_of_column_labels] -``` - -For example, run the following code to see which rows are selected: +Note that the row index is now out-of-order. Run the following code to see which rows are selected: ```{python mini-df-loc, exercise = TRUE, exercise.setup = "pandas-setup"} mini_df = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'Main_Condition']).head(4) @@ -913,97 +1178,90 @@ mini_df_sort = mini_df.sort_values(by = 'Main_Condition') mini_df_sort.loc[[0, 2],['Main_Condition']] ``` -The first list (`[0, 2]`) instructs `.loc[]` to select the rows labelled `0` and `2` in order. The second list (`['Main_Condition']`) instructs `.loc[]` to select only the column labelled `Main_Condition`. - -#### Using `.iloc[]` - -The `.iloc[]` index works using the *position* of the rows and columns, instead of their labels: +The first list (`[0, 2]`) instructs `.loc[]` to select the rows **labelled** as `0` and `2` in order. The second list (`['Main_Condition']`) instructs `.loc[]` to select only the column labelled `Main_Condition`. -```{python iloc, eval = FALSE, echo = TRUE} -df.iloc[list_of_row_positions, list_of_column_positions] -``` +So note that `.loc[]` does the selection based on index labels. It selects the rows **labelled** as `0` and `2` instead of the actual first and third rows. -where +### Selecting Ranges of Rows -- both the row positions and column positions start at `0` -- rows are counted top to bottom -- columns are counted left to right +Instead of specifying lists of rows and columns we can specify a **slice**, which is like saying `select all rows from row A to row B`. -For example, run the following code to see which rows are selected: +Slices using `.loc` include the label after the `:` in the slice syntax: `start_label:stop_label`, which will include -```{python mini-df-iloc, exercise = TRUE, exercise.setup = "pandas-setup"} -mini_df = pd.read_csv("data/borders_inc_age.csv", usecols = ['URI', 'Main_Condition']).head(4) +- the row/column labelled `start_label` +- the row/column labelled `stop_label` +- all rows/columns in between -mini_df_sort = mini_df.sort_values(by = 'Main_Condition') +Let's use `.loc` to select the same section of `borders`. This is how the data looks like after sorting by `Main_Condition`: -mini_df_sort.iloc[[0, 2],[1]] +```{python slice-loc1, echo = FALSE} +borders = borders.sort_values(by = 'Main_Condition') +borders ``` -Here, the list (`[0, 2]`) instructs `.iloc[]` to select only the first row (position `0`) and the third row (position `2`). The column list `[1]` instructs `.iloc[]` to select the second column, which is the column labelled `Main_Condition`. - -### Selecting Ranges of Rows - -Instead of specifying lists of rows and columns with `.loc/.iloc`, we can specify a **slice**, which is like saying `select all rows from row A to row B`. +Again we will need two slices: -#### Slices with `.iloc` +- **rows**: the first four rows start at the label `5018` and end at `23180`. The slice is `5018:23180` and will include rows labelled `5018`, `6671`, `3420` and `23180`. Note how the `stop_label` is included. +- **columns**: the first column to include is labelled `HospitalCode` and the last is `ManagementofPatient`. The slice is `'HospitalCode':'ManagementofPatient'` and will include columns labelled `HospitalCode`, `Specialty` and `ManagementofPatient`. -A slice reproduces a consecutive list by specifying where to start and stop, using the syntax `start_position:stop_position`, where +```{python slice-loc2, exercise = TRUE, exercise.setup = "pandas-setup"} +borders = borders.sort_values(by = 'Main_Condition') +borders.loc[5018:23180,'HospitalCode':'ManagementofPatient'] +``` -- `start_position` is the first position to include -- `stop_position` is one position *beyond* the last position to include +### Open-Ended Slices -For example, to reproduce our list `[0, 1, 2, 3, 4]`, we would use the slice `0:5` to indicate: +If we don't want to specify a start value, the slice will start at the first label. Similarly, if we don't specify an end value, the slice will end at the final label. For example, the `.loc` slice `'HospitalCode':` will include every column starting at `HospitalCode` through to the final column of the DataFrame. -- start at position `0` -- stop before position `5` -- include all positions in-between (`1`, `2`, `3`, `4`) +If we specify neither the start nor the final value, the slice will include all rows and columns. For example, the code `borders.loc[0:2,:]` will include rows labelled as `0`, `1` and `2`, along with every column. -We want to select the first 4 rows and the `HospitalCode`, `Specialty`, and `ManagementofPatient` (second to fourth) columns from `borders` after sorting the data by `Main_Condition`. We will need two slices, one for the rows and one for the columns: +### Selecting Rows Using `query()` -- **rows**: we want to start at the first row (postion `0`) and end *before* the fifth row (position `4`). The slice is `0:4` and will include positions `0`, `1`, `2` and `3`. -- **columns**: we want to start at the second column (position `1`) and end *before* the fifth column (position `4`). The slice is `1:4` and will include positions `1`, `2` and `3`. +An easy way to filter rows in a DataFrame is to use `query()` in Pandas. Instead of juggling multiple `&` (and), `|` (or), and parentheses, you can just write your condition like plain English. The basic syntax is: -```{python slice-iloc, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = borders.sort_values(by = 'Main_Condition') -borders.iloc[0:4,1:4] +```{python query1, eval = FALSE, echo = TRUE} +df.query('condition') ``` -#### Slices with `.loc` +where -Unlike `.iloc`, slices using `.loc` include the label after the `:` in the slice syntax: `start_label:stop_label`, which will include +- **`df`** is your Pandas DataFrame. +- **`query()`** is the method you’re calling. +- **`'condition'`** is a string where you define your filtering logic. -- the row/column labelled `start_label` -- the row/column labelled `stop_label` -- all rows/columns in between +For example we want to filter the `HospitalCode` is `B120H` for the first 10 rows +from `borders`. -Let's use `.loc` to select the same section of `borders`. This is how the data looks like after soring by `Main_Condition`: +```{python query2, exercise = TRUE, exercise.setup = "pandas-setup"} +result = borders.head(10).query('HospitalCode == "B120H"') -```{python slice-loc1, echo = FALSE} -borders = borders.sort_values(by = 'Main_Condition') -borders +print(result) ``` -Again we will need two slices: +Note that two `=` signs performs the comparison, and one `=` performs the assignment to the variable. -- **rows**: the first four rows start at the label `5018` and end at `23180`. The slice is `5018:23180` and will include rows labelled `5018`, `6671`, `3420` and `23180`. Note how the `stop_label` is included, unlike with `.iloc`. -- **columns**: the first column to include is labelled `HospitalCode` and the last is `ManagementofPatient`. The slice is `'HospitalCode':'ManagementofPatient'` and will include columns labelled `HospitalCode`, `Specialty` and `ManagementofPatient`. +You can also use logical operators (`and`, `or`, `not`) in query to filter with +multiple conditions. -```{python slice-loc2, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = borders.sort_values(by = 'Main_Condition') -borders.loc[5018:23180,'HospitalCode':'ManagementofPatient'] -``` +- Use `and` for **both** conditions to be true. +- Use `or` when **either** condition can be true. +- Use `not` to **exclude** specific conditions. -#### Open-Ended Slices +For example we want to filter the `HospitalCode` is `B120H` and `Specialty` as `A1` +for the first 10 rows from `borders`. -If we don't want to specify a start value, the slice will start at the first position/label. For example, the `.iloc` slice `:3` would include rows at positions `0`, `1` and `2`. +```{python query3, exercise = TRUE, exercise.setup = "pandas-setup"} +result = borders.head(10).query('HospitalCode == "B120H" and Specialty == "A1"') -Similarly, if we don't specify an end value, the slice will end at the final position/label. For example, the `.loc` slice `'HospitalCode':` will include every column starting at `HospitalCode` through to the final column of the DataFrame. +print(result) +``` -If we specify neither the start nor the final value, the slice will include all rows and columns. For example, the code `borders.iloc[0:2,:]` will include rows at positions `0` and `1` along with every column. +Please note that in `query()`, you should always use `and`, `or`, and `not`, instead of +`&`, `|` and `~`. ### Boolean Masks -We often need to select data by properties, instead of by position/index. For example we might want to select all rows in `borders` corresponding to the HospitalCode as `B120H`. We can achieve this using Python's [comparison operators](#comparisonoperators) to compare values. Whenever we compare two variables using a comparison operator, Python returns a `True` if the comparison is correct, and a `False` if it is incorrect. +We often need to select data by properties, instead of by position/index. For example we might want to select all rows in `borders` corresponding to the HospitalCode as `B120H`. We can achieve this using Python's comparison operators to compare values. Whenever we compare two variables using a comparison operator, Python returns a `True` if the comparison is correct, and a `False` if it is incorrect. For example, here are a few comparisons and their output: @@ -1035,8 +1293,6 @@ It can be helpful to assign a Boolean mask to a variable. For example let's assi is_hosp = (borders.head(10)['HospitalCode'] == 'B120H') ``` -Note that two `=` signs performs the comparison, and one `=` performs the assignment to the variable. - ### Filtering Rows with Booleans A Boolean mask tells us which rows have a certain property. What we usually want is to actually filter the DataFrame down to only those rows where Boolean mask is `True`. We can pass the mask to the DataFrame: @@ -1047,9 +1303,9 @@ is_hosp = (borders.head(10)['HospitalCode'] == 'B120H') borders.head(10)[is_hosp] ``` -### Combining Booleans with And +### Booleans with Logical Operators -We may want to filter the rows where patients are from hospital `B120H` with certain specialty (e.g. `A1`). Under this case the two comparisons can be combined with `and` to test if both are simultaneously true. Pandas uses the symbol `&` for this. Let's perform the row selection by combining the comparisons for the first 10 rows from `borders`: +We may want to filter the rows where patients are from hospital `B120H` with certain specialty (e.g. `A1`). Similar to use `query()`, the two comparisons can be combined with `and` to test if both are simultaneously true. Pandas uses the symbol `&` for this. Let's perform the row selection by combining the comparisons for the first 10 rows from `borders`: ```{python boolean-mask7, exercise = TRUE, exercise.setup = "pandas-setup"} is_hosp = (borders.head(10)['HospitalCode'] == 'B120H') #assign the first condition to a variable @@ -1061,9 +1317,7 @@ borders.head(10)[is_hosp & is_spec] Note that if there are no rows match the conditions, filtering the DataFrame will produce a result with column labels in the header but no actual rows. -### Combining Booleans with Or - -In Python, `or` behaves the same way: it outputs `True` as long as **one of** the combined comparisons is `True`. Pandas uses the symbol `|` instead of `or`. If we use `|` for the example above, which rows will be selected? +In Python, `or` outputs `True` as long as **one of** the combined comparisons is `True`. Pandas uses the symbol `|` instead of `or`. If we use `|` for the example above, which rows will be selected? ```{python boolean-mask8, exercise = TRUE, exercise.setup = "pandas-setup"} is_hosp = (borders.head(10)['HospitalCode'] == 'B120H') #assign the first condition to a variable @@ -1075,8 +1329,6 @@ borders.head(10)[is_hosp | is_spec] We can see the rows where either hospital is `B120H` or specialty is `A1` are filtered this time, as long as one of the conditions is met. -### Inverting Booleans with Not - What if we want to select the rows where specialty is **not** `A1`? Pandas uses the symbol `~` for `not/non` to exclude the rows we don't want: ```{python boolean-mask9, exercise = TRUE, exercise.setup = "pandas-setup"} @@ -1087,7 +1339,7 @@ not_spec = ~is_spec #create a new Boolean mask to invert the pre-existing mask borders.head(10)[not_spec] ``` -You can see the rows with specialty `A1` are excluded. `~` simply swaps `True` and `False`. +You can see the rows with specialty `A1` are excluded. `~` simply swaps `True` and `False`. ### Add/Delete a Column @@ -1107,18 +1359,25 @@ borders['number_of_eyebrows'] = 2 borders.head() ``` -Sometimes we want to delete certain columns. We can use `drop` method to do so. +Sometimes we want to delete certain columns. We can use `drop` method to do so. * Removing a column by label: -```{python remove-column1, eval = FALSE, echo = TRUE} -df = df.drop(list_of_column_labels, axis = 1) -# axis = 1 specifies you are removing a column +```{python delete-column1, eval = FALSE, echo = TRUE} +df = df.drop('column_name', axis = 1) +``` + +where `1` is the *axis* number (`0` for rows and `1` for columns). + +Or `drop` method accepts `index/columns` keywords as an alternative to specifying the axis. So we can now just do: + +```{python delete-column2, eval = FALSE, echo = TRUE} +df = df.drop(columns = ['column_nameA', 'column_nameB']) ``` Let's load the first 10 rows of `borders`, and remove the first two columns `URI` and `HospitalCode` by their column labels (column names): -```{python delete-column1, exercise = TRUE, exercise.setup = "pandas-setup"} +```{python delete-column-example1, exercise = TRUE, exercise.setup = "pandas-setup"} borders_10 = borders.head(10) borders_10.drop(['URI', 'HospitalCode'], axis = 1) @@ -1126,19 +1385,29 @@ borders_10.drop(['URI', 'HospitalCode'], axis = 1) * Removing a column by index position: -```{python remove-column2, eval = FALSE, echo = TRUE} +```{python delete-column3, eval = FALSE, echo = TRUE} df = df.drop(df.columns[list_of_column_positions], axis = 1) -# axis = 1 specifies you are removing a column ``` Let's replicate the last example by using this method: -```{python delete-column2, exercise = TRUE, exercise.setup = "pandas-setup"} +```{python delete-column-example2, exercise = TRUE, exercise.setup = "pandas-setup"} borders_10 = borders.head(10) borders_10.drop(borders_10.columns[[0, 1]], axis = 1) ``` +Besides, if you want to delete the column without having to reassign `df` you can add `inplace = True` as mentioned before: + +```{python delete-column4, eval = FALSE, echo = TRUE} +# Delete a single column +df.drop('column_name', axis = 1, inplace = True) + +# Delete multiple columns +df.drop(['column_nameA', 'column_nameB'], axis = 1, inplace = True) +``` + + ## Wrangle – Part 2 ### Manipulate Strings @@ -1151,12 +1420,12 @@ There are a number of ways to manipulate strings in Python. Here are a few metho df['column_name'] = df['column_name'].str.split('delimiter') ``` -For example, we would like to split the strings in the column `ManagementofPatient` at the value `a`. +For example, we would like to split the strings in the column `birthdate` at the value `/`. ```{python split_value_example, exercise = TRUE, exercise.setup = "pandas-setup"} -borders_data['ManagementofPatient'] = borders_data['ManagementofPatient'].str.split('a') +borders['birthdate'] = borders['birthdate'].str.split('/') -print(borders_data) +print(borders['birthdate']) ``` There are some other commonly used string methods: @@ -1177,12 +1446,10 @@ df['column_name'] = df['column_name'].str.lower() df['column_name'] = df['column_name'].str.replace('old_value','new_value') ``` -In the exercise below, read the borders_inc_age csv in, then replace all instances of `B120H` in the `HospitalCode` column with the phrase `BRILLIANT`. +For example, we want to replace all instances of `B120H` in the `HospitalCode` column with `MarkedHospital`. ```{python manipulate-string, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = pd.read_csv("data/borders_inc_age.csv") - -borders['HospitalCode'] = borders['HospitalCode'].str.replace('B120H','BRILLIANT') +borders['HospitalCode'] = borders['HospitalCode'].str.replace('B120H','MarkedHospital') # View the result borders.head(10) @@ -1196,7 +1463,7 @@ Another way to recode data which offers more flexibility is by using the `loc` a df.loc[df['column_name'] == existing_value, 'column_name'] = new_value ``` -This method uses the boolean [operator](#comparisonoperators) `==`, which means **equal to**. We can also apply other operators. +This method uses the boolean operator `==` which means **equal to**. We can also apply other operators. For example, in the case that you wish to find all the values which are less than `5` in a given column, and replace them with `Small number`, you would code the following: @@ -1204,15 +1471,10 @@ For example, in the case that you wish to find all the values which are less tha df.loc[df['column_name'] < 5, 'column_name'] = 'Small number' ``` -As you can imagine, this methods affords a great level of versatility in data analysis. - -In the exercise below, read in the `borders_inc_age` csv file, and recode all instances of `B120H` in the `HospitalCode` column to `Recoded`. - +We can repeat the example of recoding all instances of `B120H` in the `HospitalCode` column to `MarkedHospital`. ```{python recode-exercise, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = pd.read_csv("data/borders_inc_age.csv") - -borders.loc[borders['HospitalCode'] == 'B120H', 'HospitalCode'] = 'Recoded' +borders.loc[borders['HospitalCode'] == 'B120H', 'HospitalCode'] = 'MarkedHospital' # View the result borders.head(10) @@ -1220,24 +1482,22 @@ borders.head(10) ### Rename -Sometimes we would like to renames specific columns in a data frame: +Sometimes we would like to rename specific columns in a data frame: ```{python rename, eval = FALSE, echo = TRUE} df.rename(columns = {'old_column_name':'new_column_name'}) ``` -For example, the column `HospitalCode` in `borders_data` doesn't follow the style guide, let's rename it to `Hospital_Code`. +For example, let's rename `HospitalCode` to `Hospital_Code` in `borders`. ```{python rename-exercise, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = pd.read_csv("data/borders_inc_age.csv") - borders = borders.rename(columns = {'HospitalCode':'Hospital_Code'}) # View the result borders.head(10) ``` -### Group By +### Group By and Aggregate The `groupby()` function in Pandas allows us to split a Dataframe into groups based on one or more keys, such as column values, and then perform operations on them, such as aggregations or transformations: @@ -1252,8 +1512,6 @@ borders = pd.read_csv("data/borders_inc_age.csv") borders.groupby('HospitalCode') ``` -### Aggregate Dataframe - After assigning `groupby()` function to a new variable, we can apply the aggregate `agg()` function to conduct operations on specific columns. ```{python aggregate1, eval = FALSE, echo = TRUE} @@ -1275,55 +1533,66 @@ grouped_variable.agg({'column1' : ['function1','function2','function3'], For example, We want to find the `mean`, `max`, `count` and `sum` of the `LengthOfStay` variables, grouped by `HospitalCode`. -First let's store the above `borders_data.groupby('HospitalCode')` into a new variable called `grouped_by_hospital_code`, and then use `agg()` to get the results. -```{python aggregate-example, eval = FALSE, echo = TRUE} -grouped_by_hospital_code.agg({'LengthOfStay': ['mean','max','count','sum']}) -``` +First let's store the above `borders.groupby('HospitalCode')` into a new variable called `group_by_hospital_code`, and then use `agg()` to get the results. -We could also more easily use the `describe()` function within the `agg()` function detailed above. +```{python aggregate-exercise1, exercise = TRUE, exercise.setup = "pandas-setup"} +group_by_hospital_code = borders.groupby('HospitalCode') +group_by_hospital_code.agg({'LengthOfStay': ['mean','max','count','sum']}) +``` -Give that a go: Read in the `borders_inc_age` csv file, then group by `HospitalCode`, storing that into a variable called `grouped_by_hospital_code`. Aggregate using the method above. Use the `describe()` function to find important values from the `LengthOfStay` column. +We could also more easily use the `describe()` function within the `agg()` to get more statistical results: -```{python aggregate-exercise, exercise = TRUE, exercise.setup = "pandas-setup"} -borders = pd.read_csv("data/borders_inc_age.csv") +```{python aggregate-exercise2, exercise = TRUE, exercise.setup = "pandas-setup"} group_by_hospital_code = borders.groupby('HospitalCode') group_by_hospital_code.agg({'LengthOfStay':'describe'}) ``` -### Merge Dataframe +### Joining Dataframe ```{r join-diagrams-overview, echo=FALSE, fig.align='center', out.width="100%"} knitr::include_graphics("images/join_python.png") ``` -* `left` - taking all records from the "left", `data_frame_1`, and adding matched records from the "right", `data_frame_2`, introducing `NaN` where the "right", `data_2` had no matching records -* `right` - taking all records from the "right", `data_frame_2`, and adding matched records from the "left", `data_frame_1`, introducing `NaN` where the "left", `data_frame_1` had no matching records -* `inner` - producing only records where there were matches on both given data sets -* `full` - retaining all records from both data sets and introducing `na` on either one where there was no matching records +- **left** - taking all records from the "left", `data_frame_1`, and adding matched records from the "right", `data_frame_2`, introducing `NaN` where the "right", `data_2` had no matching records +- **right** - taking all records from the "right", `data_frame_2`, and adding matched records from the "left", `data_frame_1`, introducing `NaN` where the "left", `data_frame_1` had no matching records +- **inner** - producing only records where there were matches on both given data sets +- **full/outer** - retaining all records from both data sets and introducing `na` on either one where there was no matching records By default, the merge type will be `inner` unless stated otherwise. -You define the merge/join type by defining the `how = ''`. +You define the merge/join type by defining the `how = 'join_type'`. -You should further define what common columns/variables the data frames should merge `on` by defining the `on = ['column']` +You should further define what common columns/variables the DataFrames should merge `on` by defining the `on = ['column']`: ```{python merge, eval = FALSE, echo = TRUE} df1.merge(df2, how = 'join_type', on = ['column1' , 'column2']) ``` -2 new data-sets have been loaded, `baby5` and `baby6`, these have common variables `FAMILYID` and `DOB`. Using a `left` join, merge them together. +Two data-sets have been loaded, `baby5` and `baby6`, which have common variables `FAMILYID` and `DOB`. Using a `left` join, merge them together. ```{python merge-exercise, exercise = TRUE, exercise.setup = "pandas-setup"} -borders_data = pd.read_csv("data/borders_inc_age.csv") baby5 = pd.read_csv("data/Baby5.csv") baby6 = pd.read_csv("data/Baby6.csv") baby5.merge(baby6, how = 'left', on = ['FAMILYID','DOB']) ``` + ## Help & Feedback -#### Feedback +### Help + +- [PHS Data and Intelligence Forum - Python](https://teams.microsoft.com/l/channel/19%3Ade96dc64d9204809b76b068c71ba3543%40thread.tacv2/Python?groupId=ec4250f9-b70a-4f32-9372-a232ccb4f713&tenantId=10efe0bd-a030-4bca-809c-b5e6745e499a) + +- [KIND Network Open Source Week: Introduction to Python](https://vimeo.com/1140086541) + +- [PEP 8 Style Guide for Python](https://peps.python.org/pep-0008/) + +- [W3 Schools Python Tutorial](https://www.w3schools.com/python/default.asp) + +- [Codecademy Getting Started with Python for Data Science](https://www.codecademy.com/enrolled/courses/getting-started-with-python-for-data-science) + +### Feedback - + diff --git a/python-training.Rproj b/python-training.Rproj index 3af27f6..8e3c2eb 100755 --- a/python-training.Rproj +++ b/python-training.Rproj @@ -1,13 +1,13 @@ -Version: 1.0 - -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default - -EnableCodeIndexing: Yes -UseSpacesForTab: Yes -NumSpacesForTab: 2 -Encoding: UTF-8 - -RnwWeave: Sweave -LaTeX: pdfLaTeX +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX diff --git a/renv.lock b/renv.lock new file mode 100644 index 0000000..9228f9b --- /dev/null +++ b/renv.lock @@ -0,0 +1,1908 @@ +{ + "R": { + "Version": "4.5.1", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://ppm-prod.publichealthscotland.org/cran/latest" + }, + { + "Name": "PHS GitHub", + "URL": "https://ppm-prod.publichealthscotland.org/phs-github/latest" + } + ] + }, + "Packages": { + "Matrix": { + "Package": "Matrix", + "Version": "1.7-3", + "Source": "Repository", + "VersionNote": "do also bump src/version.h, inst/include/Matrix/version.h", + "Date": "2025-03-05", + "Priority": "recommended", + "Title": "Sparse and Dense Matrix Classes and Methods", + "Description": "A rich hierarchy of sparse and dense matrix classes, including general, symmetric, triangular, and diagonal matrices with numeric, logical, or pattern entries. Efficient methods for operating on such matrices, often wrapping the 'BLAS', 'LAPACK', and 'SuiteSparse' libraries.", + "License": "GPL (>= 2) | file LICENCE", + "URL": "https://Matrix.R-forge.R-project.org", + "BugReports": "https://R-forge.R-project.org/tracker/?atid=294&group_id=61", + "Contact": "Matrix-authors@R-project.org", + "Authors@R": "c(person(\"Douglas\", \"Bates\", role = \"aut\", comment = c(ORCID = \"0000-0001-8316-9503\")), person(\"Martin\", \"Maechler\", role = c(\"aut\", \"cre\"), email = \"mmaechler+Matrix@gmail.com\", comment = c(ORCID = \"0000-0002-8685-9910\")), person(\"Mikael\", \"Jagan\", role = \"aut\", comment = c(ORCID = \"0000-0002-3542-2938\")), person(\"Timothy A.\", \"Davis\", role = \"ctb\", comment = c(ORCID = \"0000-0001-7614-6899\", \"SuiteSparse libraries\", \"collaborators listed in dir(system.file(\\\"doc\\\", \\\"SuiteSparse\\\", package=\\\"Matrix\\\"), pattern=\\\"License\\\", full.names=TRUE, recursive=TRUE)\")), person(\"George\", \"Karypis\", role = \"ctb\", comment = c(ORCID = \"0000-0003-2753-1437\", \"METIS library\", \"Copyright: Regents of the University of Minnesota\")), person(\"Jason\", \"Riedy\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4345-4200\", \"GNU Octave's condest() and onenormest()\", \"Copyright: Regents of the University of California\")), person(\"Jens\", \"Oehlschlägel\", role = \"ctb\", comment = \"initial nearPD()\"), person(\"R Core Team\", role = \"ctb\", comment = c(ROR = \"02zz1nj61\", \"base R's matrix implementation\")))", + "Depends": [ + "R (>= 4.4)", + "methods" + ], + "Imports": [ + "grDevices", + "graphics", + "grid", + "lattice", + "stats", + "utils" + ], + "Suggests": [ + "MASS", + "datasets", + "sfsmisc", + "tools" + ], + "Enhances": [ + "SparseM", + "graph" + ], + "LazyData": "no", + "LazyDataNote": "not possible, since we use data/*.R and our S4 classes", + "BuildResaveData": "no", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Douglas Bates [aut] (), Martin Maechler [aut, cre] (), Mikael Jagan [aut] (), Timothy A. Davis [ctb] (, SuiteSparse libraries, collaborators listed in dir(system.file(\"doc\", \"SuiteSparse\", package=\"Matrix\"), pattern=\"License\", full.names=TRUE, recursive=TRUE)), George Karypis [ctb] (, METIS library, Copyright: Regents of the University of Minnesota), Jason Riedy [ctb] (, GNU Octave's condest() and onenormest(), Copyright: Regents of the University of California), Jens Oehlschlägel [ctb] (initial nearPD()), R Core Team [ctb] (02zz1nj61, base R's matrix implementation)", + "Maintainer": "Martin Maechler ", + "Repository": "CRAN" + }, + "R6": { + "Package": "R6", + "Version": "2.6.1", + "Source": "Repository", + "Title": "Encapsulated Classes with Reference Semantics", + "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Creates classes with reference semantics, similar to R's built-in reference classes. Compared to reference classes, R6 classes are simpler and lighter-weight, and they are not built on S4 classes so they do not require the methods package. These classes allow public and private members, and they support inheritance, even when the classes are defined in different packages.", + "License": "MIT + file LICENSE", + "URL": "https://r6.r-lib.org, https://github.com/r-lib/R6", + "BugReports": "https://github.com/r-lib/R6/issues", + "Depends": [ + "R (>= 3.6)" + ], + "Suggests": [ + "lobstr", + "testthat (>= 3.0.0)" + ], + "Config/Needs/website": "tidyverse/tidytemplate, ggplot2, microbenchmark, scales", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2", + "NeedsCompilation": "no", + "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]", + "Maintainer": "Winston Chang ", + "Repository": "CRAN" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.1.1-1.1", + "Source": "Repository", + "Title": "Seamless R and C++ Integration", + "Date": "2026-04-19", + "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Romain\", \"Francois\", role = \"aut\", comment = c(ORCID = \"0000-0002-2444-4226\")), person(\"JJ\", \"Allaire\", role = \"aut\", comment = c(ORCID = \"0000-0003-0174-9868\")), person(\"Kevin\", \"Ushey\", role = \"aut\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Qiang\", \"Kou\", role = \"aut\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Nathan\", \"Russell\", role = \"aut\"), person(\"Iñaki\", \"Ucar\", role = \"aut\", comment = c(ORCID = \"0000-0001-6403-5550\")), person(\"Doug\", \"Bates\", role = \"aut\", comment = c(ORCID = \"0000-0001-8316-9503\")), person(\"John\", \"Chambers\", role = \"aut\"))", + "Description": "The 'Rcpp' package provides R functions as well as C++ classes which offer a seamless integration of R and C++. Many R data types and objects can be mapped back and forth to C++ equivalents which facilitates both writing of new code as well as easier integration of third-party libraries. Documentation about 'Rcpp' is provided by several vignettes included in this package, via the 'Rcpp Gallery' site at , the paper by Eddelbuettel and Francois (2011, ), the book by Eddelbuettel (2013, ) and the paper by Eddelbuettel and Balamuta (2018, ); see 'citation(\"Rcpp\")' for details.", + "Depends": [ + "R (>= 3.5.0)" + ], + "Imports": [ + "methods", + "utils" + ], + "Suggests": [ + "tinytest", + "inline", + "rbenchmark", + "pkgKitten (>= 0.1.2)" + ], + "URL": "https://www.rcpp.org, https://dirk.eddelbuettel.com/code/rcpp.html, https://github.com/RcppCore/Rcpp", + "License": "GPL (>= 2)", + "BugReports": "https://github.com/RcppCore/Rcpp/issues", + "MailingList": "rcpp-devel@lists.r-forge.r-project.org", + "RoxygenNote": "6.1.1", + "Encoding": "UTF-8", + "VignetteBuilder": "Rcpp", + "NeedsCompilation": "yes", + "Author": "Dirk Eddelbuettel [aut, cre] (ORCID: ), Romain Francois [aut] (ORCID: ), JJ Allaire [aut] (ORCID: ), Kevin Ushey [aut] (ORCID: ), Qiang Kou [aut] (ORCID: ), Nathan Russell [aut], Iñaki Ucar [aut] (ORCID: ), Doug Bates [aut] (ORCID: ), John Chambers [aut]", + "Maintainer": "Dirk Eddelbuettel ", + "Repository": "CRAN" + }, + "RcppTOML": { + "Package": "RcppTOML", + "Version": "0.2.3", + "Source": "Repository", + "Type": "Package", + "Title": "'Rcpp' Bindings to Parser for \"Tom's Obvious Markup Language\"", + "Date": "2025-03-08", + "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Mark\", \"Gillard\", role = \"aut\", comment = \"Author of 'toml++' header library\"))", + "Description": "The configuration format defined by 'TOML' (which expands to \"Tom's Obvious Markup Language\") specifies an excellent format (described at ) suitable for both human editing as well as the common uses of a machine-readable format. This package uses 'Rcpp' to connect to the 'toml++' parser written by Mark Gillard to R.", + "SystemRequirements": "A C++17 compiler", + "BugReports": "https://github.com/eddelbuettel/rcpptoml/issues", + "URL": "http://dirk.eddelbuettel.com/code/rcpp.toml.html", + "Imports": [ + "Rcpp (>= 1.0.8)" + ], + "Depends": [ + "R (>= 3.3.0)" + ], + "LinkingTo": [ + "Rcpp" + ], + "Suggests": [ + "tinytest" + ], + "License": "GPL (>= 2)", + "NeedsCompilation": "yes", + "Author": "Dirk Eddelbuettel [aut, cre] (), Mark Gillard [aut] (Author of 'toml++' header library)", + "Maintainer": "Dirk Eddelbuettel ", + "Repository": "CRAN" + }, + "backports": { + "Package": "backports", + "Version": "1.5.1", + "Source": "Repository", + "Type": "Package", + "Title": "Reimplementations of Functions Introduced Since R-3.0.0", + "Authors@R": "c( person(\"Michel\", \"Lang\", NULL, \"michellang@gmail.com\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Duncan\", \"Murdoch\", NULL, \"murdoch.duncan@gmail.com\", role = c(\"aut\")), person(\"R Core Team\", role = \"aut\"))", + "Maintainer": "Michel Lang ", + "Description": "Functions introduced or changed since R v3.0.0 are re-implemented in this package. The backports are conditionally exported in order to let R resolve the function name to either the implemented backport, or the respective base version, if available. Package developers can make use of new functions or arguments by selectively importing specific backports to support older installations.", + "URL": "https://github.com/r-lib/backports", + "BugReports": "https://github.com/r-lib/backports/issues", + "License": "GPL-2 | GPL-3", + "NeedsCompilation": "yes", + "ByteCompile": "yes", + "Depends": [ + "R (>= 3.0.0)" + ], + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "Author": "Michel Lang [cre, aut] (ORCID: ), Duncan Murdoch [aut], R Core Team [aut]", + "Repository": "CRAN" + }, + "base64enc": { + "Package": "base64enc", + "Version": "0.1-6", + "Source": "Repository", + "Title": "Tools for 'base64' Encoding", + "Author": "Simon Urbanek [aut, cre, cph] (https://urbanek.nz, ORCID: )", + "Authors@R": "person(\"Simon\", \"Urbanek\", role=c(\"aut\",\"cre\",\"cph\"), email=\"Simon.Urbanek@r-project.org\", comment=c(\"https://urbanek.nz\", ORCID=\"0000-0003-2297-1732\"))", + "Maintainer": "Simon Urbanek ", + "Depends": [ + "R (>= 2.9.0)" + ], + "Enhances": [ + "png" + ], + "Description": "Tools for handling 'base64' encoding. It is more flexible than the orphaned 'base64' package.", + "License": "GPL-2 | GPL-3", + "URL": "https://www.rforge.net/base64enc", + "BugReports": "https://github.com/s-u/base64enc/issues", + "NeedsCompilation": "yes", + "Repository": "CRAN", + "Encoding": "UTF-8" + }, + "bslib": { + "Package": "bslib", + "Version": "0.11.0", + "Source": "Repository", + "Title": "Custom 'Bootstrap' 'Sass' Themes for 'shiny' and 'rmarkdown'", + "Authors@R": "c( person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Garrick\", \"Aden-Buie\", , \"garrick@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-7111-0077\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Javi\", \"Aguilar\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap colorpicker library\"), person(\"Thomas\", \"Park\", role = c(\"ctb\", \"cph\"), comment = \"Bootswatch library\"), person(, \"PayPal\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap accessibility plugin\") )", + "Description": "Simplifies custom 'CSS' styling of both 'shiny' and 'rmarkdown' via 'Bootstrap' 'Sass'. Supports 'Bootstrap' 3, 4 and 5 as well as their various 'Bootswatch' themes. An interactive widget is also provided for previewing themes in real time.", + "License": "MIT + file LICENSE", + "URL": "https://rstudio.github.io/bslib/, https://github.com/rstudio/bslib", + "BugReports": "https://github.com/rstudio/bslib/issues", + "Depends": [ + "R (>= 2.10)" + ], + "Imports": [ + "base64enc", + "cachem", + "fastmap (>= 1.1.1)", + "grDevices", + "htmltools (>= 0.5.8)", + "jquerylib (>= 0.1.3)", + "jsonlite", + "lifecycle", + "memoise (>= 2.0.1)", + "mime", + "rlang", + "sass (>= 0.4.9)" + ], + "Suggests": [ + "brand.yml", + "bsicons", + "curl", + "fontawesome", + "future", + "ggplot2", + "knitr", + "lattice", + "magrittr", + "rappdirs", + "rmarkdown (>= 2.7)", + "shiny (>= 1.11.1.9000)", + "testthat", + "thematic", + "tools", + "utils", + "withr", + "yaml" + ], + "Config/Needs/deploy": "BH, chiflights22, colourpicker, commonmark, cpp11, cpsievert/chiflights22, cpsievert/histoslider, dplyr, DT, ggplot2, ggridges, gt, hexbin, histoslider, htmlwidgets, lattice, leaflet, lubridate, markdown, modelr, plotly, reactable, reshape2, rprojroot, rsconnect, rstudio/shiny, scales, styler, tibble", + "Config/Needs/routine": "chromote, desc, renv", + "Config/Needs/website": "brio, crosstalk, dplyr, DT, ggplot2, glue, htmlwidgets, leaflet, lorem, palmerpenguins, plotly, purrr, rprojroot, rstudio/htmltools, scales, stringr, tidyr, webshot2", + "Config/roxygen2/version": "8.0.0", + "Config/testthat/edition": "3", + "Config/testthat/parallel": "true", + "Config/testthat/start-first": "zzzz-bs-sass, fonts, zzz-precompile, theme-*, rmd-*", + "Encoding": "UTF-8", + "Collate": "'accordion.R' 'breakpoints.R' 'bs-current-theme.R' 'bs-dependencies.R' 'bs-global.R' 'bs-remove.R' 'bs-theme-layers.R' 'bs-theme-preset-bootswatch.R' 'bs-theme-preset-brand.R' 'bs-theme-preset-builtin.R' 'bs-theme-preset.R' 'utils.R' 'bs-theme-preview.R' 'bs-theme-update.R' 'bs-theme.R' 'bslib-package.R' 'buttons.R' 'card.R' 'deprecated.R' 'files.R' 'fill.R' 'imports.R' 'input-code-editor.R' 'input-dark-mode.R' 'input-submit.R' 'input-switch.R' 'layout.R' 'nav-items.R' 'nav-update.R' 'navbar_options.R' 'navs-legacy.R' 'navs.R' 'onLoad.R' 'page.R' 'popover.R' 'precompiled.R' 'print.R' 'shiny-devmode.R' 'sidebar.R' 'staticimports.R' 'toast.R' 'toolbar.R' 'tooltip.R' 'utils-deps.R' 'utils-shiny.R' 'utils-tags.R' 'value-box.R' 'version-default.R' 'versions.R'", + "NeedsCompilation": "no", + "Author": "Carson Sievert [aut, cre] (ORCID: ), Joe Cheng [aut], Garrick Aden-Buie [aut] (ORCID: ), Posit Software, PBC [cph, fnd], Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Javi Aguilar [ctb, cph] (Bootstrap colorpicker library), Thomas Park [ctb, cph] (Bootswatch library), PayPal [ctb, cph] (Bootstrap accessibility plugin)", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "cachem": { + "Package": "cachem", + "Version": "1.1.0", + "Source": "Repository", + "Title": "Cache R Objects with Automatic Pruning", + "Description": "Key-value stores with automatic pruning. Caches can limit either their total size or the age of the oldest object (or both), automatically pruning objects to maintain the constraints.", + "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", c(\"aut\", \"cre\")), person(family = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")))", + "License": "MIT + file LICENSE", + "Encoding": "UTF-8", + "ByteCompile": "true", + "URL": "https://cachem.r-lib.org/, https://github.com/r-lib/cachem", + "Imports": [ + "rlang", + "fastmap (>= 1.2.0)" + ], + "Suggests": [ + "testthat" + ], + "RoxygenNote": "7.2.3", + "Config/Needs/routine": "lobstr", + "Config/Needs/website": "pkgdown", + "NeedsCompilation": "yes", + "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]", + "Maintainer": "Winston Chang ", + "Repository": "CRAN" + }, + "checkmate": { + "Package": "checkmate", + "Version": "2.3.4", + "Source": "Repository", + "Type": "Package", + "Title": "Fast and Versatile Argument Checks", + "Description": "Tests and assertions to perform frequent argument checks. A substantial part of the package was written in C to minimize any worries about execution time overhead.", + "Authors@R": "c( person(\"Michel\", \"Lang\", NULL, \"michellang@gmail.com\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Bernd\", \"Bischl\", NULL, \"bernd_bischl@gmx.net\", role = \"ctb\"), person(\"Dénes\", \"Tóth\", NULL, \"toth.denes@kogentum.hu\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4262-3217\")) )", + "URL": "https://mllg.github.io/checkmate/, https://github.com/mllg/checkmate", + "URLNote": "https://github.com/mllg/checkmate", + "BugReports": "https://github.com/mllg/checkmate/issues", + "NeedsCompilation": "yes", + "ByteCompile": "yes", + "Encoding": "UTF-8", + "Depends": [ + "R (>= 3.0.0)" + ], + "Imports": [ + "backports (>= 1.1.0)", + "utils" + ], + "Suggests": [ + "R6", + "fastmatch", + "data.table (>= 1.9.8)", + "devtools", + "ggplot2", + "knitr", + "magrittr", + "microbenchmark", + "rmarkdown", + "testthat (>= 3.0.4)", + "tinytest (>= 1.1.0)", + "tibble" + ], + "License": "BSD_3_clause + file LICENSE", + "VignetteBuilder": "knitr", + "RoxygenNote": "7.3.3", + "Collate": "'AssertCollection.R' 'allMissing.R' 'anyInfinite.R' 'anyMissing.R' 'anyNaN.R' 'asInteger.R' 'assert.R' 'helper.R' 'makeExpectation.R' 'makeTest.R' 'makeAssertion.R' 'checkAccess.R' 'checkArray.R' 'checkAtomic.R' 'checkAtomicVector.R' 'checkCharacter.R' 'checkChoice.R' 'checkClass.R' 'checkComplex.R' 'checkCount.R' 'checkDataFrame.R' 'checkDataTable.R' 'checkDate.R' 'checkDirectoryExists.R' 'checkDisjunct.R' 'checkDouble.R' 'checkEnvironment.R' 'checkFALSE.R' 'checkFactor.R' 'checkFileExists.R' 'checkFlag.R' 'checkFormula.R' 'checkFunction.R' 'checkInt.R' 'checkInteger.R' 'checkIntegerish.R' 'checkList.R' 'checkLogical.R' 'checkMatrix.R' 'checkMultiClass.R' 'checkNamed.R' 'checkNames.R' 'checkNull.R' 'checkNumber.R' 'checkNumeric.R' 'checkOS.R' 'checkPOSIXct.R' 'checkPathForOutput.R' 'checkPermutation.R' 'checkR6.R' 'checkRaw.R' 'checkScalar.R' 'checkScalarNA.R' 'checkSetEqual.R' 'checkString.R' 'checkSubset.R' 'checkTRUE.R' 'checkTibble.R' 'checkVector.R' 'coalesce.R' 'isIntegerish.R' 'matchArg.R' 'qassert.R' 'qassertr.R' 'vname.R' 'wfwl.R' 'zzz.R'", + "Author": "Michel Lang [cre, aut] (ORCID: ), Bernd Bischl [ctb], Dénes Tóth [ctb] (ORCID: )", + "Maintainer": "Michel Lang ", + "Repository": "CRAN" + }, + "cli": { + "Package": "cli", + "Version": "3.6.6", + "Source": "Repository", + "Title": "Helpers for Developing Command Line Interfaces", + "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"gabor@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Kirill\", \"Müller\", role = \"ctb\"), person(\"Salim\", \"Brüggemann\", , \"salim-b@pm.me\", role = \"ctb\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "A suite of tools to build attractive command line interfaces ('CLIs'), from semantic elements: headings, lists, alerts, paragraphs, etc. Supports custom themes via a 'CSS'-like language. It also contains a number of lower level 'CLI' elements: rules, boxes, trees, and 'Unicode' symbols with 'ASCII' alternatives. It support ANSI colors and text styles as well.", + "License": "MIT + file LICENSE", + "URL": "https://cli.r-lib.org, https://github.com/r-lib/cli", + "BugReports": "https://github.com/r-lib/cli/issues", + "Depends": [ + "R (>= 3.4)" + ], + "Imports": [ + "utils" + ], + "Suggests": [ + "callr", + "covr", + "crayon", + "digest", + "glue (>= 1.6.0)", + "grDevices", + "htmltools", + "htmlwidgets", + "knitr", + "methods", + "processx", + "ps (>= 1.3.4.9000)", + "rlang (>= 1.0.2.9003)", + "rmarkdown", + "rprojroot", + "rstudioapi", + "testthat (>= 3.2.0)", + "tibble", + "whoami", + "withr" + ], + "Config/Needs/website": "r-lib/asciicast, bench, brio, cpp11, decor, desc, fansi, prettyunits, sessioninfo, tidyverse/tidytemplate, usethis, vctrs", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-04-25", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2.9000", + "NeedsCompilation": "yes", + "Author": "Gábor Csárdi [aut, cre], Hadley Wickham [ctb], Kirill Müller [ctb], Salim Brüggemann [ctb] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Gábor Csárdi ", + "Repository": "CRAN" + }, + "commonmark": { + "Package": "commonmark", + "Version": "2.0.0", + "Source": "Repository", + "Type": "Package", + "Title": "High Performance CommonMark and Github Markdown Rendering in R", + "Authors@R": "c( person(\"Jeroen\", \"Ooms\", ,\"jeroenooms@gmail.com\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"John MacFarlane\", role = \"cph\", comment = \"Author of cmark\"))", + "Description": "The CommonMark specification defines a rationalized version of markdown syntax. This package uses the 'cmark' reference implementation for converting markdown text into various formats including html, latex and groff man. In addition it exposes the markdown parse tree in xml format. Also includes opt-in support for GFM extensions including tables, autolinks, and strikethrough text.", + "License": "BSD_2_clause + file LICENSE", + "URL": "https://docs.ropensci.org/commonmark/ https://ropensci.r-universe.dev/commonmark", + "BugReports": "https://github.com/r-lib/commonmark/issues", + "Suggests": [ + "curl", + "testthat", + "xml2" + ], + "RoxygenNote": "7.3.2", + "Language": "en-US", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Jeroen Ooms [aut, cre] (ORCID: ), John MacFarlane [cph] (Author of cmark)", + "Maintainer": "Jeroen Ooms ", + "Repository": "CRAN" + }, + "digest": { + "Package": "digest", + "Version": "0.6.39", + "Source": "Repository", + "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Antoine\", \"Lucas\", role=\"ctb\", comment = c(ORCID = \"0000-0002-8059-9767\")), person(\"Jarek\", \"Tuszynski\", role=\"ctb\"), person(\"Henrik\", \"Bengtsson\", role=\"ctb\", comment = c(ORCID = \"0000-0002-7579-5165\")), person(\"Simon\", \"Urbanek\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2297-1732\")), person(\"Mario\", \"Frasca\", role=\"ctb\"), person(\"Bryan\", \"Lewis\", role=\"ctb\"), person(\"Murray\", \"Stokely\", role=\"ctb\"), person(\"Hannes\", \"Muehleisen\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8552-0029\")), person(\"Duncan\", \"Murdoch\", role=\"ctb\"), person(\"Jim\", \"Hester\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Wush\", \"Wu\", role=\"ctb\", comment = c(ORCID = \"0000-0001-5180-0567\")), person(\"Qiang\", \"Kou\", role=\"ctb\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Thierry\", \"Onkelinx\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8804-4216\")), person(\"Michel\", \"Lang\", role=\"ctb\", comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Viliam\", \"Simko\", role=\"ctb\"), person(\"Kurt\", \"Hornik\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4198-9911\")), person(\"Radford\", \"Neal\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2473-3407\")), person(\"Kendon\", \"Bell\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9093-8312\")), person(\"Matthew\", \"de Queljoe\", role=\"ctb\"), person(\"Dmitry\", \"Selivanov\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0492-6647\")), person(\"Ion\", \"Suruceanu\", role=\"ctb\", comment = c(ORCID = \"0009-0005-6446-4909\")), person(\"Bill\", \"Denney\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5759-428X\")), person(\"Dirk\", \"Schumacher\", role=\"ctb\"), person(\"András\", \"Svraka\", role=\"ctb\", comment = c(ORCID = \"0009-0008-8480-1329\")), person(\"Sergey\", \"Fedorov\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5970-7233\")), person(\"Will\", \"Landau\", role=\"ctb\", comment = c(ORCID = \"0000-0003-1878-3253\")), person(\"Floris\", \"Vanderhaeghe\", role=\"ctb\", comment = c(ORCID = \"0000-0002-6378-6229\")), person(\"Kevin\", \"Tappe\", role=\"ctb\"), person(\"Harris\", \"McGehee\", role=\"ctb\"), person(\"Tim\", \"Mastny\", role=\"ctb\"), person(\"Aaron\", \"Peikert\", role=\"ctb\", comment = c(ORCID = \"0000-0001-7813-818X\")), person(\"Mark\", \"van der Loo\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9807-4686\")), person(\"Chris\", \"Muir\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2555-3878\")), person(\"Moritz\", \"Beller\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4852-0526\")), person(\"Sebastian\", \"Campbell\", role=\"ctb\", comment = c(ORCID = \"0009-0000-5948-4503\")), person(\"Winston\", \"Chang\", role=\"ctb\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Dean\", \"Attali\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5645-3493\")), person(\"Michael\", \"Chirico\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0787-087X\")), person(\"Kevin\", \"Ushey\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Carl\", \"Pearson\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0701-7860\")))", + "Date": "2025-11-19", + "Title": "Create Compact Hash Digests of R Objects", + "Description": "Implementation of a function 'digest()' for the creation of hash digests of arbitrary R objects (using the 'md5', 'sha-1', 'sha-256', 'crc32', 'xxhash', 'murmurhash', 'spookyhash', 'blake3', 'crc32c', 'xxh3_64', and 'xxh3_128' algorithms) permitting easy comparison of R language objects, as well as functions such as 'hmac()' to create hash-based message authentication code. Please note that this package is not meant to be deployed for cryptographic purposes for which more comprehensive (and widely tested) libraries such as 'OpenSSL' should be used.", + "URL": "https://github.com/eddelbuettel/digest, https://eddelbuettel.github.io/digest/, https://dirk.eddelbuettel.com/code/digest.html", + "BugReports": "https://github.com/eddelbuettel/digest/issues", + "Depends": [ + "R (>= 3.3.0)" + ], + "Imports": [ + "utils" + ], + "License": "GPL (>= 2)", + "Suggests": [ + "tinytest", + "simplermarkdown", + "rbenchmark" + ], + "VignetteBuilder": "simplermarkdown", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Dirk Eddelbuettel [aut, cre] (ORCID: ), Antoine Lucas [ctb] (ORCID: ), Jarek Tuszynski [ctb], Henrik Bengtsson [ctb] (ORCID: ), Simon Urbanek [ctb] (ORCID: ), Mario Frasca [ctb], Bryan Lewis [ctb], Murray Stokely [ctb], Hannes Muehleisen [ctb] (ORCID: ), Duncan Murdoch [ctb], Jim Hester [ctb] (ORCID: ), Wush Wu [ctb] (ORCID: ), Qiang Kou [ctb] (ORCID: ), Thierry Onkelinx [ctb] (ORCID: ), Michel Lang [ctb] (ORCID: ), Viliam Simko [ctb], Kurt Hornik [ctb] (ORCID: ), Radford Neal [ctb] (ORCID: ), Kendon Bell [ctb] (ORCID: ), Matthew de Queljoe [ctb], Dmitry Selivanov [ctb] (ORCID: ), Ion Suruceanu [ctb] (ORCID: ), Bill Denney [ctb] (ORCID: ), Dirk Schumacher [ctb], András Svraka [ctb] (ORCID: ), Sergey Fedorov [ctb] (ORCID: ), Will Landau [ctb] (ORCID: ), Floris Vanderhaeghe [ctb] (ORCID: ), Kevin Tappe [ctb], Harris McGehee [ctb], Tim Mastny [ctb], Aaron Peikert [ctb] (ORCID: ), Mark van der Loo [ctb] (ORCID: ), Chris Muir [ctb] (ORCID: ), Moritz Beller [ctb] (ORCID: ), Sebastian Campbell [ctb] (ORCID: ), Winston Chang [ctb] (ORCID: ), Dean Attali [ctb] (ORCID: ), Michael Chirico [ctb] (ORCID: ), Kevin Ushey [ctb] (ORCID: ), Carl Pearson [ctb] (ORCID: )", + "Maintainer": "Dirk Eddelbuettel ", + "Repository": "CRAN" + }, + "evaluate": { + "Package": "evaluate", + "Version": "1.0.5", + "Source": "Repository", + "Type": "Package", + "Title": "Parsing and Evaluation Tools that Provide More Details than the Default", + "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\")), person(\"Yihui\", \"Xie\", role = \"aut\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Michael\", \"Lawrence\", role = \"ctb\"), person(\"Thomas\", \"Kluyver\", role = \"ctb\"), person(\"Jeroen\", \"Ooms\", role = \"ctb\"), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Adam\", \"Ryczkowski\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Michel\", \"Lang\", role = \"ctb\"), person(\"Karolis\", \"Koncevičius\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Parsing and evaluation tools that make it easy to recreate the command line behaviour of R.", + "License": "MIT + file LICENSE", + "URL": "https://evaluate.r-lib.org/, https://github.com/r-lib/evaluate", + "BugReports": "https://github.com/r-lib/evaluate/issues", + "Depends": [ + "R (>= 3.6.0)" + ], + "Suggests": [ + "callr", + "covr", + "ggplot2 (>= 3.3.6)", + "lattice", + "methods", + "pkgload", + "ragg (>= 1.4.0)", + "rlang (>= 1.1.5)", + "knitr", + "testthat (>= 3.0.0)", + "withr" + ], + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2", + "NeedsCompilation": "no", + "Author": "Hadley Wickham [aut, cre], Yihui Xie [aut] (ORCID: ), Michael Lawrence [ctb], Thomas Kluyver [ctb], Jeroen Ooms [ctb], Barret Schloerke [ctb], Adam Ryczkowski [ctb], Hiroaki Yutani [ctb], Michel Lang [ctb], Karolis Koncevičius [ctb], Posit Software, PBC [cph, fnd]", + "Maintainer": "Hadley Wickham ", + "Repository": "CRAN" + }, + "fastmap": { + "Package": "fastmap", + "Version": "1.2.0", + "Source": "Repository", + "Title": "Fast Data Structures", + "Authors@R": "c( person(\"Winston\", \"Chang\", email = \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(given = \"Tessil\", role = \"cph\", comment = \"hopscotch_map library\") )", + "Description": "Fast implementation of data structures, including a key-value store, stack, and queue. Environments are commonly used as key-value stores in R, but every time a new key is used, it is added to R's global symbol table, causing a small amount of memory leakage. This can be problematic in cases where many different keys are used. Fastmap avoids this memory leak issue by implementing the map using data structures in C++.", + "License": "MIT + file LICENSE", + "Encoding": "UTF-8", + "RoxygenNote": "7.2.3", + "Suggests": [ + "testthat (>= 2.1.1)" + ], + "URL": "https://r-lib.github.io/fastmap/, https://github.com/r-lib/fastmap", + "BugReports": "https://github.com/r-lib/fastmap/issues", + "NeedsCompilation": "yes", + "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd], Tessil [cph] (hopscotch_map library)", + "Maintainer": "Winston Chang ", + "Repository": "CRAN" + }, + "fontawesome": { + "Package": "fontawesome", + "Version": "0.5.3", + "Source": "Repository", + "Type": "Package", + "Title": "Easily Work with 'Font Awesome' Icons", + "Description": "Easily and flexibly insert 'Font Awesome' icons into 'R Markdown' documents and 'Shiny' apps. These icons can be inserted into HTML content through inline 'SVG' tags or 'i' tags. There is also a utility function for exporting 'Font Awesome' icons as 'PNG' images for those situations where raster graphics are needed.", + "Authors@R": "c( person(\"Richard\", \"Iannone\", , \"rich@posit.co\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"ctb\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome font\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "License": "MIT + file LICENSE", + "URL": "https://github.com/rstudio/fontawesome, https://rstudio.github.io/fontawesome/", + "BugReports": "https://github.com/rstudio/fontawesome/issues", + "Encoding": "UTF-8", + "ByteCompile": "true", + "RoxygenNote": "7.3.2", + "Depends": [ + "R (>= 3.3.0)" + ], + "Imports": [ + "rlang (>= 1.0.6)", + "htmltools (>= 0.5.1.1)" + ], + "Suggests": [ + "covr", + "dplyr (>= 1.0.8)", + "gt (>= 0.9.0)", + "knitr (>= 1.31)", + "testthat (>= 3.0.0)", + "rsvg" + ], + "Config/testthat/edition": "3", + "NeedsCompilation": "no", + "Author": "Richard Iannone [aut, cre] (), Christophe Dervieux [ctb] (), Winston Chang [ctb], Dave Gandy [ctb, cph] (Font-Awesome font), Posit Software, PBC [cph, fnd]", + "Maintainer": "Richard Iannone ", + "Repository": "CRAN" + }, + "fs": { + "Package": "fs", + "Version": "1.6.7", + "Source": "Repository", + "Title": "Cross-Platform File System Operations Based on 'libuv'", + "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Hadley\", \"Wickham\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", role = \"aut\"), person(\"Jeroen\", \"Ooms\", , \"jeroenooms@gmail.com\", role = \"cre\"), person(\"libuv project contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Joyent, Inc. and other Node contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "A cross-platform interface to file system operations, built on top of the 'libuv' C library.", + "License": "MIT + file LICENSE", + "URL": "https://fs.r-lib.org, https://github.com/r-lib/fs", + "BugReports": "https://github.com/r-lib/fs/issues", + "Depends": [ + "R (>= 4.1)" + ], + "Imports": [ + "methods" + ], + "Suggests": [ + "covr", + "crayon", + "knitr", + "pillar (>= 1.0.0)", + "rmarkdown", + "spelling", + "testthat (>= 3.0.0)", + "tibble (>= 1.1.0)", + "vctrs (>= 0.3.0)", + "withr" + ], + "VignetteBuilder": "knitr", + "ByteCompile": "true", + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-04-23", + "Copyright": "file COPYRIGHTS", + "Encoding": "UTF-8", + "Language": "en-US", + "RoxygenNote": "7.3.3", + "SystemRequirements": "GNU make", + "NeedsCompilation": "yes", + "Author": "Jim Hester [aut], Hadley Wickham [aut], Gábor Csárdi [aut], Jeroen Ooms [cre], libuv project contributors [cph] (libuv library), Joyent, Inc. and other Node contributors [cph] (libuv library), Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Jeroen Ooms ", + "Repository": "RSPM" + }, + "glue": { + "Package": "glue", + "Version": "1.8.1", + "Source": "Repository", + "Title": "Interpreted String Literals", + "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Jennifer\", \"Bryan\", , \"jenny@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-6983-2759\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "An implementation of interpreted string literals, inspired by Python's Literal String Interpolation and Docstrings and Julia's Triple-Quoted String Literals .", + "License": "MIT + file LICENSE", + "URL": "https://glue.tidyverse.org/, https://github.com/tidyverse/glue", + "BugReports": "https://github.com/tidyverse/glue/issues", + "Depends": [ + "R (>= 4.1)" + ], + "Imports": [ + "methods" + ], + "Suggests": [ + "crayon", + "DBI (>= 1.2.0)", + "dplyr", + "knitr", + "rlang", + "rmarkdown", + "RSQLite", + "testthat (>= 3.2.0)", + "vctrs (>= 0.3.0)", + "waldo (>= 0.5.3)", + "withr" + ], + "VignetteBuilder": "knitr", + "ByteCompile": "true", + "Config/Needs/website": "bench, forcats, ggbeeswarm, ggplot2, R.utils, rprintf, tidyr, tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2026-04-16", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "yes", + "Author": "Jim Hester [aut] (ORCID: ), Jennifer Bryan [aut, cre] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Jennifer Bryan ", + "Repository": "RSPM" + }, + "here": { + "Package": "here", + "Version": "1.0.2", + "Source": "Repository", + "Title": "A Simpler Way to Find Your Files", + "Date": "2025-09-06", + "Authors@R": "c(person(given = \"Kirill\", family = \"M\\u00fcller\", role = c(\"aut\", \"cre\"), email = \"kirill@cynkra.com\", comment = c(ORCID = \"0000-0002-1416-3412\")), person(given = \"Jennifer\", family = \"Bryan\", role = \"ctb\", email = \"jenny@rstudio.com\", comment = c(ORCID = \"0000-0002-6983-2759\")))", + "Description": "Constructs paths to your project's files. Declare the relative path of a file within your project with 'i_am()'. Use the 'here()' function as a drop-in replacement for 'file.path()', it will always locate the files relative to your project root.", + "License": "MIT + file LICENSE", + "URL": "https://here.r-lib.org/, https://github.com/r-lib/here", + "BugReports": "https://github.com/r-lib/here/issues", + "Imports": [ + "rprojroot (>= 2.1.0)" + ], + "Suggests": [ + "conflicted", + "covr", + "fs", + "knitr", + "palmerpenguins", + "plyr", + "readr", + "rlang", + "rmarkdown", + "testthat", + "uuid", + "withr" + ], + "VignetteBuilder": "knitr", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3.9000", + "Config/testthat/edition": "3", + "Config/Needs/website": "tidyverse/tidytemplate", + "NeedsCompilation": "no", + "Author": "Kirill Müller [aut, cre] (ORCID: ), Jennifer Bryan [ctb] (ORCID: )", + "Maintainer": "Kirill Müller ", + "Repository": "CRAN" + }, + "highr": { + "Package": "highr", + "Version": "0.12", + "Source": "Repository", + "Type": "Package", + "Title": "Syntax Highlighting for R Source Code", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Yixuan\", \"Qiu\", role = \"aut\"), person(\"Christopher\", \"Gandrud\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\") )", + "Description": "Provides syntax highlighting for R source code. Currently it supports LaTeX and HTML output. Source code of other languages is supported via Andre Simon's highlight package ().", + "Depends": [ + "R (>= 3.3.0)" + ], + "Imports": [ + "xfun (>= 0.18)" + ], + "Suggests": [ + "knitr", + "markdown", + "testit" + ], + "License": "GPL", + "URL": "https://github.com/yihui/highr", + "BugReports": "https://github.com/yihui/highr/issues", + "VignetteBuilder": "knitr", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "no", + "Author": "Yihui Xie [aut, cre] (ORCID: ), Yixuan Qiu [aut], Christopher Gandrud [ctb], Qiang Li [ctb]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "htmltools": { + "Package": "htmltools", + "Version": "0.5.9", + "Source": "Repository", + "Type": "Package", + "Title": "Tools for HTML", + "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Yihui\", \"Xie\", , \"yihui@posit.co\", role = \"aut\"), person(\"Jeff\", \"Allen\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Tools for HTML generation and output.", + "License": "GPL (>= 2)", + "URL": "https://github.com/rstudio/htmltools, https://rstudio.github.io/htmltools/", + "BugReports": "https://github.com/rstudio/htmltools/issues", + "Depends": [ + "R (>= 2.14.1)" + ], + "Imports": [ + "base64enc", + "digest", + "fastmap (>= 1.1.0)", + "grDevices", + "rlang (>= 1.0.0)", + "utils" + ], + "Suggests": [ + "Cairo", + "markdown", + "ragg", + "shiny", + "testthat", + "withr" + ], + "Enhances": [ + "knitr" + ], + "Config/Needs/check": "knitr", + "Config/Needs/website": "rstudio/quillt, bench", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "Collate": "'colors.R' 'fill.R' 'html_dependency.R' 'html_escape.R' 'html_print.R' 'htmltools-package.R' 'images.R' 'known_tags.R' 'selector.R' 'staticimports.R' 'tag_query.R' 'utils.R' 'tags.R' 'template.R'", + "NeedsCompilation": "yes", + "Author": "Joe Cheng [aut], Carson Sievert [aut, cre] (ORCID: ), Barret Schloerke [aut] (ORCID: ), Winston Chang [aut] (ORCID: ), Yihui Xie [aut], Jeff Allen [aut], Posit Software, PBC [cph, fnd]", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "htmlwidgets": { + "Package": "htmlwidgets", + "Version": "1.6.4", + "Source": "Repository", + "Type": "Package", + "Title": "HTML Widgets for R", + "Authors@R": "c( person(\"Ramnath\", \"Vaidyanathan\", role = c(\"aut\", \"cph\")), person(\"Yihui\", \"Xie\", role = \"aut\"), person(\"JJ\", \"Allaire\", role = \"aut\"), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Kenton\", \"Russell\", role = c(\"aut\", \"cph\")), person(\"Ellis\", \"Hughes\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "A framework for creating HTML widgets that render in various contexts including the R console, 'R Markdown' documents, and 'Shiny' web applications.", + "License": "MIT + file LICENSE", + "URL": "https://github.com/ramnathv/htmlwidgets", + "BugReports": "https://github.com/ramnathv/htmlwidgets/issues", + "Imports": [ + "grDevices", + "htmltools (>= 0.5.7)", + "jsonlite (>= 0.9.16)", + "knitr (>= 1.8)", + "rmarkdown", + "yaml" + ], + "Suggests": [ + "testthat" + ], + "Enhances": [ + "shiny (>= 1.1)" + ], + "VignetteBuilder": "knitr", + "Encoding": "UTF-8", + "RoxygenNote": "7.2.3", + "NeedsCompilation": "no", + "Author": "Ramnath Vaidyanathan [aut, cph], Yihui Xie [aut], JJ Allaire [aut], Joe Cheng [aut], Carson Sievert [aut, cre] (), Kenton Russell [aut, cph], Ellis Hughes [ctb], Posit Software, PBC [cph, fnd]", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "httpuv": { + "Package": "httpuv", + "Version": "1.6.17", + "Source": "Repository", + "Type": "Package", + "Title": "HTTP and WebSocket Server Library", + "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")), person(\"Hector\", \"Corrada Bravo\", role = \"ctb\"), person(\"Jeroen\", \"Ooms\", role = \"ctb\"), person(\"Andrzej\", \"Krzemienski\", role = \"cph\", comment = \"optional.hpp\"), person(\"libuv project contributors\", role = \"cph\", comment = \"libuv library, see src/libuv/AUTHORS file\"), person(\"Joyent, Inc. and other Node contributors\", role = \"cph\", comment = \"libuv library, see src/libuv/AUTHORS file; and http-parser library, see src/http-parser/AUTHORS file\"), person(\"Niels\", \"Provos\", role = \"cph\", comment = \"libuv subcomponent: tree.h\"), person(\"Internet Systems Consortium, Inc.\", role = \"cph\", comment = \"libuv subcomponent: inet_pton and inet_ntop, contained in src/libuv/src/inet.c\"), person(\"Alexander\", \"Chemeris\", role = \"cph\", comment = \"libuv subcomponent: stdint-msvc2008.h (from msinttypes)\"), person(\"Google, Inc.\", role = \"cph\", comment = \"libuv subcomponent: pthread-fixes.c\"), person(\"Sony Mobile Communcations AB\", role = \"cph\", comment = \"libuv subcomponent: pthread-fixes.c\"), person(\"Berkeley Software Design Inc.\", role = \"cph\", comment = \"libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c\"), person(\"Kenneth\", \"MacKay\", role = \"cph\", comment = \"libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c\"), person(\"Emergya (Cloud4all, FP7/2007-2013, grant agreement no 289016)\", role = \"cph\", comment = \"libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c\"), person(\"Steve\", \"Reid\", role = \"aut\", comment = \"SHA-1 implementation\"), person(\"James\", \"Brown\", role = \"aut\", comment = \"SHA-1 implementation\"), person(\"Bob\", \"Trower\", role = \"aut\", comment = \"base64 implementation\"), person(\"Alexander\", \"Peslyak\", role = \"aut\", comment = \"MD5 implementation\"), person(\"Trantor Standard Systems\", role = \"cph\", comment = \"base64 implementation\"), person(\"Igor\", \"Sysoev\", role = \"cph\", comment = \"http-parser\") )", + "Description": "Provides low-level socket and protocol support for handling HTTP and WebSocket requests directly from within R. It is primarily intended as a building block for other packages, rather than making it particularly easy to create complete web applications using httpuv alone. httpuv is built on top of the libuv and http-parser C libraries, both of which were developed by Joyent, Inc. (See LICENSE file for libuv and http-parser license information.)", + "License": "GPL (>= 2) | file LICENSE", + "URL": "https://rstudio.github.io/httpuv/, https://github.com/rstudio/httpuv", + "BugReports": "https://github.com/rstudio/httpuv/issues", + "Depends": [ + "R (>= 2.15.1)" + ], + "Imports": [ + "later (>= 0.8.0)", + "promises", + "R6", + "Rcpp (>= 1.0.7)", + "utils" + ], + "Suggests": [ + "callr", + "curl", + "jsonlite", + "testthat (>= 3.0.0)", + "websocket" + ], + "LinkingTo": [ + "later", + "Rcpp" + ], + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-07-01", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "SystemRequirements": "GNU make, zlib", + "Collate": "'RcppExports.R' 'httpuv-package.R' 'httpuv.R' 'random_port.R' 'server.R' 'staticServer.R' 'static_paths.R' 'utils.R'", + "NeedsCompilation": "yes", + "Author": "Joe Cheng [aut], Winston Chang [aut, cre], Posit, PBC [cph, fnd] (ROR: ), Hector Corrada Bravo [ctb], Jeroen Ooms [ctb], Andrzej Krzemienski [cph] (optional.hpp), libuv project contributors [cph] (libuv library, see src/libuv/AUTHORS file), Joyent, Inc. and other Node contributors [cph] (libuv library, see src/libuv/AUTHORS file; and http-parser library, see src/http-parser/AUTHORS file), Niels Provos [cph] (libuv subcomponent: tree.h), Internet Systems Consortium, Inc. [cph] (libuv subcomponent: inet_pton and inet_ntop, contained in src/libuv/src/inet.c), Alexander Chemeris [cph] (libuv subcomponent: stdint-msvc2008.h (from msinttypes)), Google, Inc. [cph] (libuv subcomponent: pthread-fixes.c), Sony Mobile Communcations AB [cph] (libuv subcomponent: pthread-fixes.c), Berkeley Software Design Inc. [cph] (libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c), Kenneth MacKay [cph] (libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c), Emergya (Cloud4all, FP7/2007-2013, grant agreement no 289016) [cph] (libuv subcomponent: android-ifaddrs.h, android-ifaddrs.c), Steve Reid [aut] (SHA-1 implementation), James Brown [aut] (SHA-1 implementation), Bob Trower [aut] (base64 implementation), Alexander Peslyak [aut] (MD5 implementation), Trantor Standard Systems [cph] (base64 implementation), Igor Sysoev [cph] (http-parser)", + "Maintainer": "Winston Chang ", + "Repository": "CRAN" + }, + "jquerylib": { + "Package": "jquerylib", + "Version": "0.1.4", + "Source": "Repository", + "Title": "Obtain 'jQuery' as an HTML Dependency Object", + "Authors@R": "c( person(\"Carson\", \"Sievert\", role = c(\"aut\", \"cre\"), email = \"carson@rstudio.com\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", role = \"aut\", email = \"joe@rstudio.com\"), person(family = \"RStudio\", role = \"cph\"), person(family = \"jQuery Foundation\", role = \"cph\", comment = \"jQuery library and jQuery UI library\"), person(family = \"jQuery contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt\") )", + "Description": "Obtain any major version of 'jQuery' () and use it in any webpage generated by 'htmltools' (e.g. 'shiny', 'htmlwidgets', and 'rmarkdown'). Most R users don't need to use this package directly, but other R packages (e.g. 'shiny', 'rmarkdown', etc.) depend on this package to avoid bundling redundant copies of 'jQuery'.", + "License": "MIT + file LICENSE", + "Encoding": "UTF-8", + "Config/testthat/edition": "3", + "RoxygenNote": "7.0.2", + "Imports": [ + "htmltools" + ], + "Suggests": [ + "testthat" + ], + "NeedsCompilation": "no", + "Author": "Carson Sievert [aut, cre] (), Joe Cheng [aut], RStudio [cph], jQuery Foundation [cph] (jQuery library and jQuery UI library), jQuery contributors [ctb, cph] (jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt)", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "2.0.0", + "Source": "Repository", + "Title": "A Simple and Robust JSON Parser and Generator for R", + "License": "MIT + file LICENSE", + "Depends": [ + "methods" + ], + "Authors@R": "c( person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Duncan\", \"Temple Lang\", role = \"ctb\"), person(\"Lloyd\", \"Hilaiel\", role = \"cph\", comment=\"author of bundled libyajl\"))", + "URL": "https://jeroen.r-universe.dev/jsonlite https://arxiv.org/abs/1403.2805", + "BugReports": "https://github.com/jeroen/jsonlite/issues", + "Maintainer": "Jeroen Ooms ", + "VignetteBuilder": "knitr, R.rsp", + "Description": "A reasonably fast JSON parser and generator, optimized for statistical data and the web. Offers simple, flexible tools for working with JSON in R, and is particularly powerful for building pipelines and interacting with a web API. The implementation is based on the mapping described in the vignette (Ooms, 2014). In addition to converting JSON data from/to R objects, 'jsonlite' contains functions to stream, validate, and prettify JSON data. The unit tests included with the package verify that all edge cases are encoded and decoded consistently for use with dynamic data in systems and applications.", + "Suggests": [ + "httr", + "vctrs", + "testthat", + "knitr", + "rmarkdown", + "R.rsp", + "sf" + ], + "RoxygenNote": "7.3.2", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Jeroen Ooms [aut, cre] (), Duncan Temple Lang [ctb], Lloyd Hilaiel [cph] (author of bundled libyajl)", + "Repository": "https://ppm-prod.publichealthscotland.org/cran/latest" + }, + "knitr": { + "Package": "knitr", + "Version": "1.51", + "Source": "Repository", + "Type": "Package", + "Title": "A General-Purpose Package for Dynamic Report Generation in R", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Abhraneel\", \"Sarma\", role = \"ctb\"), person(\"Adam\", \"Vogt\", role = \"ctb\"), person(\"Alastair\", \"Andrew\", role = \"ctb\"), person(\"Alex\", \"Zvoleff\", role = \"ctb\"), person(\"Amar\", \"Al-Zubaidi\", role = \"ctb\"), person(\"Andre\", \"Simon\", role = \"ctb\", comment = \"the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de\"), person(\"Aron\", \"Atkins\", role = \"ctb\"), person(\"Aaron\", \"Wolen\", role = \"ctb\"), person(\"Ashley\", \"Manton\", role = \"ctb\"), person(\"Atsushi\", \"Yasumoto\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8335-495X\")), person(\"Ben\", \"Baumer\", role = \"ctb\"), person(\"Brian\", \"Diggs\", role = \"ctb\"), person(\"Brian\", \"Zhang\", role = \"ctb\"), person(\"Bulat\", \"Yapparov\", role = \"ctb\"), person(\"Cassio\", \"Pereira\", role = \"ctb\"), person(\"Christophe\", \"Dervieux\", role = \"ctb\"), person(\"David\", \"Hall\", role = \"ctb\"), person(\"David\", \"Hugh-Jones\", role = \"ctb\"), person(\"David\", \"Robinson\", role = \"ctb\"), person(\"Doug\", \"Hemken\", role = \"ctb\"), person(\"Duncan\", \"Murdoch\", role = \"ctb\"), person(\"Elio\", \"Campitelli\", role = \"ctb\"), person(\"Ellis\", \"Hughes\", role = \"ctb\"), person(\"Emily\", \"Riederer\", role = \"ctb\"), person(\"Fabian\", \"Hirschmann\", role = \"ctb\"), person(\"Fitch\", \"Simeon\", role = \"ctb\"), person(\"Forest\", \"Fang\", role = \"ctb\"), person(c(\"Frank\", \"E\", \"Harrell\", \"Jr\"), role = \"ctb\", comment = \"the Sweavel package at inst/misc/Sweavel.sty\"), person(\"Garrick\", \"Aden-Buie\", role = \"ctb\"), person(\"Gregoire\", \"Detrez\", role = \"ctb\"), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Hao\", \"Zhu\", role = \"ctb\"), person(\"Heewon\", \"Jeon\", role = \"ctb\"), person(\"Henrik\", \"Bengtsson\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Ian\", \"Lyttle\", role = \"ctb\"), person(\"Hodges\", \"Daniel\", role = \"ctb\"), person(\"Jacob\", \"Bien\", role = \"ctb\"), person(\"Jake\", \"Burkhead\", role = \"ctb\"), person(\"James\", \"Manton\", role = \"ctb\"), person(\"Jared\", \"Lander\", role = \"ctb\"), person(\"Jason\", \"Punyon\", role = \"ctb\"), person(\"Javier\", \"Luraschi\", role = \"ctb\"), person(\"Jeff\", \"Arnold\", role = \"ctb\"), person(\"Jenny\", \"Bryan\", role = \"ctb\"), person(\"Jeremy\", \"Ashkenas\", role = c(\"ctb\", \"cph\"), comment = \"the CSS file at inst/misc/docco-classic.css\"), person(\"Jeremy\", \"Stephens\", role = \"ctb\"), person(\"Jim\", \"Hester\", role = \"ctb\"), person(\"Joe\", \"Cheng\", role = \"ctb\"), person(\"Johannes\", \"Ranke\", role = \"ctb\"), person(\"John\", \"Honaker\", role = \"ctb\"), person(\"John\", \"Muschelli\", role = \"ctb\"), person(\"Jonathan\", \"Keane\", role = \"ctb\"), person(\"JJ\", \"Allaire\", role = \"ctb\"), person(\"Johan\", \"Toloe\", role = \"ctb\"), person(\"Jonathan\", \"Sidi\", role = \"ctb\"), person(\"Joseph\", \"Larmarange\", role = \"ctb\"), person(\"Julien\", \"Barnier\", role = \"ctb\"), person(\"Kaiyin\", \"Zhong\", role = \"ctb\"), person(\"Kamil\", \"Slowikowski\", role = \"ctb\"), person(\"Karl\", \"Forner\", role = \"ctb\"), person(c(\"Kevin\", \"K.\"), \"Smith\", role = \"ctb\"), person(\"Kirill\", \"Mueller\", role = \"ctb\"), person(\"Kohske\", \"Takahashi\", role = \"ctb\"), person(\"Lorenz\", \"Walthert\", role = \"ctb\"), person(\"Lucas\", \"Gallindo\", role = \"ctb\"), person(\"Marius\", \"Hofert\", role = \"ctb\"), person(\"Martin\", \"Modrák\", role = \"ctb\"), person(\"Michael\", \"Chirico\", role = \"ctb\"), person(\"Michael\", \"Friendly\", role = \"ctb\"), person(\"Michal\", \"Bojanowski\", role = \"ctb\"), person(\"Michel\", \"Kuhlmann\", role = \"ctb\"), person(\"Miller\", \"Patrick\", role = \"ctb\"), person(\"Nacho\", \"Caballero\", role = \"ctb\"), person(\"Nick\", \"Salkowski\", role = \"ctb\"), person(\"Niels Richard\", \"Hansen\", role = \"ctb\"), person(\"Noam\", \"Ross\", role = \"ctb\"), person(\"Obada\", \"Mahdi\", role = \"ctb\"), person(\"Pavel N.\", \"Krivitsky\", role = \"ctb\", comment=c(ORCID = \"0000-0002-9101-3362\")), person(\"Pedro\", \"Faria\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\"), person(\"Ramnath\", \"Vaidyanathan\", role = \"ctb\"), person(\"Richard\", \"Cotton\", role = \"ctb\"), person(\"Robert\", \"Krzyzanowski\", role = \"ctb\"), person(\"Rodrigo\", \"Copetti\", role = \"ctb\"), person(\"Romain\", \"Francois\", role = \"ctb\"), person(\"Ruaridh\", \"Williamson\", role = \"ctb\"), person(\"Sagiru\", \"Mati\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1413-3974\")), person(\"Scott\", \"Kostyshak\", role = \"ctb\"), person(\"Sebastian\", \"Meyer\", role = \"ctb\"), person(\"Sietse\", \"Brouwer\", role = \"ctb\"), person(c(\"Simon\", \"de\"), \"Bernard\", role = \"ctb\"), person(\"Sylvain\", \"Rousseau\", role = \"ctb\"), person(\"Taiyun\", \"Wei\", role = \"ctb\"), person(\"Thibaut\", \"Assus\", role = \"ctb\"), person(\"Thibaut\", \"Lamadon\", role = \"ctb\"), person(\"Thomas\", \"Leeper\", role = \"ctb\"), person(\"Tim\", \"Mastny\", role = \"ctb\"), person(\"Tom\", \"Torsney-Weir\", role = \"ctb\"), person(\"Trevor\", \"Davis\", role = \"ctb\"), person(\"Viktoras\", \"Veitas\", role = \"ctb\"), person(\"Weicheng\", \"Zhu\", role = \"ctb\"), person(\"Wush\", \"Wu\", role = \"ctb\"), person(\"Zachary\", \"Foster\", role = \"ctb\"), person(\"Zhian N.\", \"Kamvar\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1458-7108\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Provides a general-purpose tool for dynamic report generation in R using Literate Programming techniques.", + "Depends": [ + "R (>= 3.6.0)" + ], + "Imports": [ + "evaluate (>= 0.15)", + "highr (>= 0.11)", + "methods", + "tools", + "xfun (>= 0.52)", + "yaml (>= 2.1.19)" + ], + "Suggests": [ + "bslib", + "DBI (>= 0.4-1)", + "digest", + "formatR", + "gifski", + "gridSVG", + "htmlwidgets (>= 0.7)", + "jpeg", + "JuliaCall (>= 0.11.1)", + "magick", + "litedown", + "markdown (>= 1.3)", + "otel", + "otelsdk", + "png", + "ragg", + "reticulate (>= 1.4)", + "rgl (>= 0.95.1201)", + "rlang", + "rmarkdown", + "sass", + "showtext", + "styler (>= 1.2.0)", + "targets (>= 0.6.0)", + "testit", + "tibble", + "tikzDevice (>= 0.10)", + "tinytex (>= 0.56)", + "webshot", + "rstudioapi", + "svglite" + ], + "License": "GPL", + "URL": "https://yihui.org/knitr/", + "BugReports": "https://github.com/yihui/knitr/issues", + "Encoding": "UTF-8", + "VignetteBuilder": "litedown, knitr", + "SystemRequirements": "Package vignettes based on R Markdown v2 or reStructuredText require Pandoc (http://pandoc.org). The function rst2pdf() requires rst2pdf (https://github.com/rst2pdf/rst2pdf).", + "Collate": "'block.R' 'cache.R' 'citation.R' 'hooks-html.R' 'plot.R' 'utils.R' 'defaults.R' 'concordance.R' 'engine.R' 'highlight.R' 'themes.R' 'header.R' 'hooks-asciidoc.R' 'hooks-chunk.R' 'hooks-extra.R' 'hooks-latex.R' 'hooks-md.R' 'hooks-rst.R' 'hooks-textile.R' 'hooks.R' 'otel.R' 'output.R' 'package.R' 'pandoc.R' 'params.R' 'parser.R' 'pattern.R' 'rocco.R' 'spin.R' 'table.R' 'template.R' 'utils-conversion.R' 'utils-rd2html.R' 'utils-string.R' 'utils-sweave.R' 'utils-upload.R' 'utils-vignettes.R' 'zzz.R'", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "no", + "Author": "Yihui Xie [aut, cre] (ORCID: , URL: https://yihui.org), Abhraneel Sarma [ctb], Adam Vogt [ctb], Alastair Andrew [ctb], Alex Zvoleff [ctb], Amar Al-Zubaidi [ctb], Andre Simon [ctb] (the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de), Aron Atkins [ctb], Aaron Wolen [ctb], Ashley Manton [ctb], Atsushi Yasumoto [ctb] (ORCID: ), Ben Baumer [ctb], Brian Diggs [ctb], Brian Zhang [ctb], Bulat Yapparov [ctb], Cassio Pereira [ctb], Christophe Dervieux [ctb], David Hall [ctb], David Hugh-Jones [ctb], David Robinson [ctb], Doug Hemken [ctb], Duncan Murdoch [ctb], Elio Campitelli [ctb], Ellis Hughes [ctb], Emily Riederer [ctb], Fabian Hirschmann [ctb], Fitch Simeon [ctb], Forest Fang [ctb], Frank E Harrell Jr [ctb] (the Sweavel package at inst/misc/Sweavel.sty), Garrick Aden-Buie [ctb], Gregoire Detrez [ctb], Hadley Wickham [ctb], Hao Zhu [ctb], Heewon Jeon [ctb], Henrik Bengtsson [ctb], Hiroaki Yutani [ctb], Ian Lyttle [ctb], Hodges Daniel [ctb], Jacob Bien [ctb], Jake Burkhead [ctb], James Manton [ctb], Jared Lander [ctb], Jason Punyon [ctb], Javier Luraschi [ctb], Jeff Arnold [ctb], Jenny Bryan [ctb], Jeremy Ashkenas [ctb, cph] (the CSS file at inst/misc/docco-classic.css), Jeremy Stephens [ctb], Jim Hester [ctb], Joe Cheng [ctb], Johannes Ranke [ctb], John Honaker [ctb], John Muschelli [ctb], Jonathan Keane [ctb], JJ Allaire [ctb], Johan Toloe [ctb], Jonathan Sidi [ctb], Joseph Larmarange [ctb], Julien Barnier [ctb], Kaiyin Zhong [ctb], Kamil Slowikowski [ctb], Karl Forner [ctb], Kevin K. Smith [ctb], Kirill Mueller [ctb], Kohske Takahashi [ctb], Lorenz Walthert [ctb], Lucas Gallindo [ctb], Marius Hofert [ctb], Martin Modrák [ctb], Michael Chirico [ctb], Michael Friendly [ctb], Michal Bojanowski [ctb], Michel Kuhlmann [ctb], Miller Patrick [ctb], Nacho Caballero [ctb], Nick Salkowski [ctb], Niels Richard Hansen [ctb], Noam Ross [ctb], Obada Mahdi [ctb], Pavel N. Krivitsky [ctb] (ORCID: ), Pedro Faria [ctb], Qiang Li [ctb], Ramnath Vaidyanathan [ctb], Richard Cotton [ctb], Robert Krzyzanowski [ctb], Rodrigo Copetti [ctb], Romain Francois [ctb], Ruaridh Williamson [ctb], Sagiru Mati [ctb] (ORCID: ), Scott Kostyshak [ctb], Sebastian Meyer [ctb], Sietse Brouwer [ctb], Simon de Bernard [ctb], Sylvain Rousseau [ctb], Taiyun Wei [ctb], Thibaut Assus [ctb], Thibaut Lamadon [ctb], Thomas Leeper [ctb], Tim Mastny [ctb], Tom Torsney-Weir [ctb], Trevor Davis [ctb], Viktoras Veitas [ctb], Weicheng Zhu [ctb], Wush Wu [ctb], Zachary Foster [ctb], Zhian N. Kamvar [ctb] (ORCID: ), Posit Software, PBC [cph, fnd]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "later": { + "Package": "later", + "Version": "1.4.6", + "Source": "Repository", + "Type": "Package", + "Title": "Utilities for Scheduling Functions to Execute Later with Event Loops", + "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Charlie\", \"Gao\", , \"charlie.gao@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-0750-061X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")), person(\"Marcus\", \"Geelnard\", role = c(\"ctb\", \"cph\"), comment = \"TinyCThread library, https://tinycthread.github.io/\"), person(\"Evan\", \"Nemerson\", role = c(\"ctb\", \"cph\"), comment = \"TinyCThread library, https://tinycthread.github.io/\") )", + "Description": "Executes arbitrary R or C functions some time after the current time, after the R execution stack has emptied. The functions are scheduled in an event loop.", + "License": "MIT + file LICENSE", + "URL": "https://later.r-lib.org, https://github.com/r-lib/later", + "BugReports": "https://github.com/r-lib/later/issues", + "Depends": [ + "R (>= 3.5)" + ], + "Imports": [ + "Rcpp (>= 1.0.10)", + "rlang" + ], + "Suggests": [ + "knitr", + "nanonext", + "promises", + "rmarkdown", + "testthat (>= 3.0.0)" + ], + "LinkingTo": [ + "Rcpp" + ], + "VignetteBuilder": "knitr", + "Config/build/compilation-database": "true", + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-07-18", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "yes", + "Author": "Winston Chang [aut] (ORCID: ), Joe Cheng [aut], Charlie Gao [aut, cre] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: ), Marcus Geelnard [ctb, cph] (TinyCThread library, https://tinycthread.github.io/), Evan Nemerson [ctb, cph] (TinyCThread library, https://tinycthread.github.io/)", + "Maintainer": "Charlie Gao ", + "Repository": "RSPM" + }, + "lattice": { + "Package": "lattice", + "Version": "0.22-7", + "Source": "Repository", + "Date": "2025-03-31", + "Priority": "recommended", + "Title": "Trellis Graphics for R", + "Authors@R": "c(person(\"Deepayan\", \"Sarkar\", role = c(\"aut\", \"cre\"), email = \"deepayan.sarkar@r-project.org\", comment = c(ORCID = \"0000-0003-4107-1553\")), person(\"Felix\", \"Andrews\", role = \"ctb\"), person(\"Kevin\", \"Wright\", role = \"ctb\", comment = \"documentation\"), person(\"Neil\", \"Klepeis\", role = \"ctb\"), person(\"Johan\", \"Larsson\", role = \"ctb\", comment = \"miscellaneous improvements\"), person(\"Zhijian (Jason)\", \"Wen\", role = \"cph\", comment = \"filled contour code\"), person(\"Paul\", \"Murrell\", role = \"ctb\", email = \"paul@stat.auckland.ac.nz\"), person(\"Stefan\", \"Eng\", role = \"ctb\", comment = \"violin plot improvements\"), person(\"Achim\", \"Zeileis\", role = \"ctb\", comment = \"modern colors\"), person(\"Alexandre\", \"Courtiol\", role = \"ctb\", comment = \"generics for larrows, lpolygon, lrect and lsegments\") )", + "Description": "A powerful and elegant high-level data visualization system inspired by Trellis graphics, with an emphasis on multivariate data. Lattice is sufficient for typical graphics needs, and is also flexible enough to handle most nonstandard requirements. See ?Lattice for an introduction.", + "Depends": [ + "R (>= 4.0.0)" + ], + "Suggests": [ + "KernSmooth", + "MASS", + "latticeExtra", + "colorspace" + ], + "Imports": [ + "grid", + "grDevices", + "graphics", + "stats", + "utils" + ], + "Enhances": [ + "chron", + "zoo" + ], + "LazyLoad": "yes", + "LazyData": "yes", + "License": "GPL (>= 2)", + "URL": "https://lattice.r-forge.r-project.org/", + "BugReports": "https://github.com/deepayan/lattice/issues", + "NeedsCompilation": "yes", + "Author": "Deepayan Sarkar [aut, cre] (), Felix Andrews [ctb], Kevin Wright [ctb] (documentation), Neil Klepeis [ctb], Johan Larsson [ctb] (miscellaneous improvements), Zhijian (Jason) Wen [cph] (filled contour code), Paul Murrell [ctb], Stefan Eng [ctb] (violin plot improvements), Achim Zeileis [ctb] (modern colors), Alexandre Courtiol [ctb] (generics for larrows, lpolygon, lrect and lsegments)", + "Maintainer": "Deepayan Sarkar ", + "Repository": "CRAN" + }, + "learnr": { + "Package": "learnr", + "Version": "0.11.6", + "Source": "Repository", + "Type": "Package", + "Title": "Interactive Tutorials for R", + "Authors@R": "c( person(\"Garrick\", \"Aden-Buie\", , \"garrick@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-7111-0077\")), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"JJ\", \"Allaire\", , \"jj@posit.co\", role = c(\"aut\", \"ccp\")), person(\"Alexander\", \"Rossell Hayes\", , \"alex.rossellhayes@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9412-0457\")), person(\"Nischal\", \"Shrestha\", , \"nischal@posit.co\", role = \"ctb\", comment = c(ORCID = \"0000-0003-3321-1712\")), person(\"Angela\", \"Li\", , \"angelali921@gmail.com\", role = \"ctb\", comment = \"vignette\"), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\")), person(, \"Ajax.org B.V.\", role = c(\"ctb\", \"cph\"), comment = \"Ace library\"), person(\"Zeno\", \"Rocha\", role = c(\"ctb\", \"cph\"), comment = \"clipboard.js library\"), person(\"Nick\", \"Payne\", role = c(\"ctb\", \"cph\"), comment = \"Bootbox library\"), person(\"Jake\", \"Archibald\", role = c(\"ctb\", \"cph\"), comment = \"idb-keyval library\"), person(\"i18next authors\", role = c(\"ctb\", \"cph\"), comment = \"i18next library\") )", + "Description": "Create interactive tutorials using R Markdown. Use a combination of narrative, figures, videos, exercises, and quizzes to create self-paced tutorials for learning about R and R packages.", + "License": "Apache License (>= 2.0)", + "URL": "https://rstudio.github.io/learnr/, https://github.com/rstudio/learnr", + "BugReports": "https://github.com/rstudio/learnr/issues", + "Imports": [ + "checkmate", + "digest", + "evaluate", + "htmltools (>= 0.3.5)", + "htmlwidgets", + "jsonlite", + "knitr (>= 1.31)", + "lifecycle", + "markdown (>= 1.3)", + "parallel", + "promises", + "rappdirs", + "renv (>= 0.8.0)", + "rlang (>= 1.0.0)", + "rmarkdown (>= 1.12.0)", + "rprojroot", + "shiny (>= 1.0)", + "stats", + "utils", + "withr" + ], + "Suggests": [ + "bslib", + "callr", + "curl", + "DBI (>= 0.4-1)", + "httpuv", + "later", + "reticulate", + "RSQLite", + "rstudioapi (>= 0.11)", + "shinytest2", + "sortable", + "testthat (>= 3.0.3)" + ], + "VignetteBuilder": "knitr", + "Config/Needs/connect": "rsconnect", + "Config/Needs/coverage": "covr", + "Config/Needs/website": "pkgdown, tidyverse/tidytemplate", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "SystemRequirements": "pandoc (>= 1.14) - http://pandoc.org", + "NeedsCompilation": "no", + "Author": "Garrick Aden-Buie [aut, cre] (ORCID: ), Barret Schloerke [aut] (ORCID: ), JJ Allaire [aut, ccp], Alexander Rossell Hayes [aut] (ORCID: ), Nischal Shrestha [ctb] (ORCID: ), Angela Li [ctb] (vignette), Posit, PBC [cph, fnd], Ajax.org B.V. [ctb, cph] (Ace library), Zeno Rocha [ctb, cph] (clipboard.js library), Nick Payne [ctb, cph] (Bootbox library), Jake Archibald [ctb, cph] (idb-keyval library), i18next authors [ctb, cph] (i18next library)", + "Maintainer": "Garrick Aden-Buie ", + "Repository": "CRAN" + }, + "lifecycle": { + "Package": "lifecycle", + "Version": "1.0.5", + "Source": "Repository", + "Title": "Manage the Life Cycle of your Package Functions", + "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Manage the life cycle of your exported functions with shared conventions, documentation badges, and user-friendly deprecation warnings.", + "License": "MIT + file LICENSE", + "URL": "https://lifecycle.r-lib.org/, https://github.com/r-lib/lifecycle", + "BugReports": "https://github.com/r-lib/lifecycle/issues", + "Depends": [ + "R (>= 3.6)" + ], + "Imports": [ + "cli (>= 3.4.0)", + "rlang (>= 1.1.0)" + ], + "Suggests": [ + "covr", + "knitr", + "lintr (>= 3.1.0)", + "rmarkdown", + "testthat (>= 3.0.1)", + "tibble", + "tidyverse", + "tools", + "vctrs", + "withr", + "xml2" + ], + "VignetteBuilder": "knitr", + "Config/Needs/website": "tidyverse/tidytemplate, usethis", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "no", + "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut] (ORCID: ), Posit Software, PBC [cph, fnd]", + "Maintainer": "Lionel Henry ", + "Repository": "CRAN" + }, + "litedown": { + "Package": "litedown", + "Version": "0.9", + "Source": "Repository", + "Type": "Package", + "Title": "A Lightweight Version of R Markdown", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Tim\", \"Taylor\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8587-7113\")), person() )", + "Description": "Render R Markdown to Markdown (without using 'knitr'), and Markdown to lightweight HTML or 'LaTeX' documents with the 'commonmark' package (instead of 'Pandoc'). Some missing Markdown features in 'commonmark' are also supported, such as raw HTML or 'LaTeX' blocks, 'LaTeX' math, superscripts, subscripts, footnotes, element attributes, and appendices, but not all 'Pandoc' Markdown features are (or will be) supported. With additional JavaScript and CSS, you can also create HTML slides and articles. This package can be viewed as a trimmed-down version of R Markdown and 'knitr'. It does not aim at rich Markdown features or a large variety of output formats (the primary formats are HTML and 'LaTeX'). Book and website projects of multiple input documents are also supported.", + "Depends": [ + "R (>= 3.2.0)" + ], + "Imports": [ + "utils", + "commonmark (>= 2.0.0)", + "xfun (>= 0.55)" + ], + "Suggests": [ + "rbibutils", + "rstudioapi", + "tinytex" + ], + "License": "MIT + file LICENSE", + "URL": "https://github.com/yihui/litedown", + "BugReports": "https://github.com/yihui/litedown/issues", + "VignetteBuilder": "litedown", + "RoxygenNote": "7.3.3", + "Encoding": "UTF-8", + "NeedsCompilation": "no", + "Author": "Yihui Xie [aut, cre] (ORCID: , URL: https://yihui.org), Tim Taylor [ctb] (ORCID: )", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "magrittr": { + "Package": "magrittr", + "Version": "2.0.5", + "Source": "Repository", + "Type": "Package", + "Title": "A Forward-Pipe Operator for R", + "Authors@R": "c( person(\"Stefan Milton\", \"Bache\", , \"stefan@stefanbache.dk\", role = c(\"aut\", \"cph\"), comment = \"Original author and creator of magrittr\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = \"cre\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "Provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression. There is flexible support for the type of right-hand side expressions. For more information, see package vignette. To quote Rene Magritte, \"Ceci n'est pas un pipe.\"", + "License": "MIT + file LICENSE", + "URL": "https://magrittr.tidyverse.org, https://github.com/tidyverse/magrittr", + "BugReports": "https://github.com/tidyverse/magrittr/issues", + "Depends": [ + "R (>= 3.4.0)" + ], + "Suggests": [ + "covr", + "knitr", + "rlang", + "rmarkdown", + "testthat" + ], + "VignetteBuilder": "knitr", + "ByteCompile": "Yes", + "Config/Needs/website": "tidyverse/tidytemplate", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "yes", + "Author": "Stefan Milton Bache [aut, cph] (Original author and creator of magrittr), Hadley Wickham [aut], Lionel Henry [cre], Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Lionel Henry ", + "Repository": "CRAN" + }, + "markdown": { + "Package": "markdown", + "Version": "2.0", + "Source": "Repository", + "Type": "Package", + "Title": "Render Markdown with 'commonmark'", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"JJ\", \"Allaire\", role = \"aut\"), person(\"Jeffrey\", \"Horner\", role = \"aut\"), person(\"Henrik\", \"Bengtsson\", role = \"ctb\"), person(\"Jim\", \"Hester\", role = \"ctb\"), person(\"Yixuan\", \"Qiu\", role = \"ctb\"), person(\"Kohske\", \"Takahashi\", role = \"ctb\"), person(\"Adam\", \"November\", role = \"ctb\"), person(\"Nacho\", \"Caballero\", role = \"ctb\"), person(\"Jeroen\", \"Ooms\", role = \"ctb\"), person(\"Thomas\", \"Leeper\", role = \"ctb\"), person(\"Joe\", \"Cheng\", role = \"ctb\"), person(\"Andrzej\", \"Oles\", role = \"ctb\"), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "Render Markdown to full and lightweight HTML/LaTeX documents with the 'commonmark' package. This package has been superseded by 'litedown'.", + "Depends": [ + "R (>= 2.11.1)" + ], + "Imports": [ + "utils", + "xfun", + "litedown (>= 0.6)" + ], + "Suggests": [ + "knitr", + "rmarkdown (>= 2.18)", + "yaml", + "RCurl" + ], + "License": "MIT + file LICENSE", + "URL": "https://github.com/rstudio/markdown", + "BugReports": "https://github.com/rstudio/markdown/issues", + "RoxygenNote": "7.3.2", + "Encoding": "UTF-8", + "NeedsCompilation": "no", + "Author": "Yihui Xie [aut, cre] (), JJ Allaire [aut], Jeffrey Horner [aut], Henrik Bengtsson [ctb], Jim Hester [ctb], Yixuan Qiu [ctb], Kohske Takahashi [ctb], Adam November [ctb], Nacho Caballero [ctb], Jeroen Ooms [ctb], Thomas Leeper [ctb], Joe Cheng [ctb], Andrzej Oles [ctb], Posit Software, PBC [cph, fnd]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "memoise": { + "Package": "memoise", + "Version": "2.0.1", + "Source": "Repository", + "Title": "'Memoisation' of Functions", + "Authors@R": "c(person(given = \"Hadley\", family = \"Wickham\", role = \"aut\", email = \"hadley@rstudio.com\"), person(given = \"Jim\", family = \"Hester\", role = \"aut\"), person(given = \"Winston\", family = \"Chang\", role = c(\"aut\", \"cre\"), email = \"winston@rstudio.com\"), person(given = \"Kirill\", family = \"Müller\", role = \"aut\", email = \"krlmlr+r@mailbox.org\"), person(given = \"Daniel\", family = \"Cook\", role = \"aut\", email = \"danielecook@gmail.com\"), person(given = \"Mark\", family = \"Edmondson\", role = \"ctb\", email = \"r@sunholo.com\"))", + "Description": "Cache the results of a function so that when you call it again with the same arguments it returns the previously computed value.", + "License": "MIT + file LICENSE", + "URL": "https://memoise.r-lib.org, https://github.com/r-lib/memoise", + "BugReports": "https://github.com/r-lib/memoise/issues", + "Imports": [ + "rlang (>= 0.4.10)", + "cachem" + ], + "Suggests": [ + "digest", + "aws.s3", + "covr", + "googleAuthR", + "googleCloudStorageR", + "httr", + "testthat" + ], + "Encoding": "UTF-8", + "RoxygenNote": "7.1.2", + "NeedsCompilation": "no", + "Author": "Hadley Wickham [aut], Jim Hester [aut], Winston Chang [aut, cre], Kirill Müller [aut], Daniel Cook [aut], Mark Edmondson [ctb]", + "Maintainer": "Winston Chang ", + "Repository": "CRAN" + }, + "mime": { + "Package": "mime", + "Version": "0.13", + "Source": "Repository", + "Type": "Package", + "Title": "Map Filenames to MIME Types", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Jeffrey\", \"Horner\", role = \"ctb\"), person(\"Beilei\", \"Bian\", role = \"ctb\") )", + "Description": "Guesses the MIME type from a filename extension using the data derived from /etc/mime.types in UNIX-type systems.", + "Imports": [ + "tools" + ], + "License": "GPL", + "URL": "https://github.com/yihui/mime", + "BugReports": "https://github.com/yihui/mime/issues", + "RoxygenNote": "7.3.2", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Yihui Xie [aut, cre] (, https://yihui.org), Jeffrey Horner [ctb], Beilei Bian [ctb]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "otel": { + "Package": "otel", + "Version": "0.2.0", + "Source": "Repository", + "Title": "OpenTelemetry R API", + "Authors@R": "person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\"))", + "Description": "High-quality, ubiquitous, and portable telemetry to enable effective observability. OpenTelemetry is a collection of tools, APIs, and SDKs used to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior. This package implements the OpenTelemetry API: . Use this package as a dependency if you want to instrument your R package for OpenTelemetry.", + "License": "MIT + file LICENSE", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2.9000", + "Depends": [ + "R (>= 3.6.0)" + ], + "Suggests": [ + "callr", + "cli", + "glue", + "jsonlite", + "otelsdk", + "processx", + "shiny", + "spelling", + "testthat (>= 3.0.0)", + "utils", + "withr" + ], + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "URL": "https://otel.r-lib.org, https://github.com/r-lib/otel", + "Additional_repositories": "https://github.com/r-lib/otelsdk/releases/download/devel", + "BugReports": "https://github.com/r-lib/otel/issues", + "NeedsCompilation": "no", + "Author": "Gábor Csárdi [aut, cre]", + "Maintainer": "Gábor Csárdi ", + "Repository": "CRAN" + }, + "png": { + "Package": "png", + "Version": "0.1-8", + "Source": "Repository", + "Title": "Read and write PNG images", + "Author": "Simon Urbanek ", + "Maintainer": "Simon Urbanek ", + "Depends": [ + "R (>= 2.9.0)" + ], + "Description": "This package provides an easy and simple way to read, write and display bitmap images stored in the PNG format. It can read and write both files and in-memory raw vectors.", + "License": "GPL-2 | GPL-3", + "SystemRequirements": "libpng", + "URL": "http://www.rforge.net/png/", + "NeedsCompilation": "yes", + "Repository": "RSPM", + "Encoding": "UTF-8" + }, + "promises": { + "Package": "promises", + "Version": "1.5.0", + "Source": "Repository", + "Type": "Package", + "Title": "Abstractions for Promise-Based Asynchronous Programming", + "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Charlie\", \"Gao\", , \"charlie.gao@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-0750-061X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "Provides fundamental abstractions for doing asynchronous programming in R using promises. Asynchronous programming is useful for allowing a single R process to orchestrate multiple tasks in the background while also attending to something else. Semantics are similar to 'JavaScript' promises, but with a syntax that is idiomatic R.", + "License": "MIT + file LICENSE", + "URL": "https://rstudio.github.io/promises/, https://github.com/rstudio/promises", + "BugReports": "https://github.com/rstudio/promises/issues", + "Depends": [ + "R (>= 4.1.0)" + ], + "Imports": [ + "fastmap (>= 1.1.0)", + "later", + "lifecycle", + "magrittr (>= 1.5)", + "otel (>= 0.2.0)", + "R6", + "rlang" + ], + "Suggests": [ + "future (>= 1.21.0)", + "knitr", + "mirai", + "otelsdk (>= 0.2.0)", + "purrr", + "Rcpp", + "rmarkdown", + "spelling", + "testthat (>= 3.0.0)", + "vembedr" + ], + "VignetteBuilder": "knitr", + "Config/Needs/website": "rsconnect, tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-05-27", + "Encoding": "UTF-8", + "Language": "en-US", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "no", + "Author": "Joe Cheng [aut], Barret Schloerke [aut, cre] (ORCID: ), Winston Chang [aut] (ORCID: ), Charlie Gao [aut] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Barret Schloerke ", + "Repository": "CRAN" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.4", + "Source": "Repository", + "Type": "Package", + "Title": "Application Directories: Determine Where to Save Data, Caches, and Logs", + "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"trl\", \"cre\", \"cph\")), person(\"Sridhar\", \"Ratnakumar\", role = \"aut\"), person(\"Trent\", \"Mick\", role = \"aut\"), person(\"ActiveState\", role = \"cph\", comment = \"R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs\"), person(\"Eddy\", \"Petrisor\", role = \"ctb\"), person(\"Trevor\", \"Davis\", role = c(\"trl\", \"aut\"), comment = c(ORCID = \"0000-0001-6341-4639\")), person(\"Gabor\", \"Csardi\", role = \"ctb\"), person(\"Gregory\", \"Jefferis\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )", + "Description": "An easy way to determine which directories on the users computer you should use to save data, caches and logs. A port of Python's 'Appdirs' () to R.", + "License": "MIT + file LICENSE", + "URL": "https://rappdirs.r-lib.org, https://github.com/r-lib/rappdirs", + "BugReports": "https://github.com/r-lib/rappdirs/issues", + "Depends": [ + "R (>= 4.1)" + ], + "Suggests": [ + "covr", + "roxygen2", + "testthat (>= 3.2.0)", + "withr" + ], + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/usethis/last-upkeep": "2025-05-05", + "Copyright": "Original python appdirs module copyright (c) 2010 ActiveState Software Inc. R port copyright Hadley Wickham, Posit, PBC. See file LICENSE for details.", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "yes", + "Author": "Hadley Wickham [trl, cre, cph], Sridhar Ratnakumar [aut], Trent Mick [aut], ActiveState [cph] (R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs), Eddy Petrisor [ctb], Trevor Davis [trl, aut] (ORCID: ), Gabor Csardi [ctb], Gregory Jefferis [ctb], Posit Software, PBC [cph, fnd] (ROR: )", + "Maintainer": "Hadley Wickham ", + "Repository": "CRAN" + }, + "renv": { + "Package": "renv", + "Version": "1.2.3", + "Source": "Repository", + "Type": "Package", + "Title": "Project Environments", + "Authors@R": "c( person(\"Kevin\", \"Ushey\", role = c(\"aut\", \"cre\"), email = \"kevin@rstudio.com\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Hadley\", \"Wickham\", role = c(\"aut\"), email = \"hadley@rstudio.com\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "A dependency management toolkit for R. Using 'renv', you can create and manage project-local R libraries, save the state of these libraries to a 'lockfile', and later restore your library as required. Together, these tools can help make your projects more isolated, portable, and reproducible.", + "License": "MIT + file LICENSE", + "URL": "https://rstudio.github.io/renv/, https://github.com/rstudio/renv", + "BugReports": "https://github.com/rstudio/renv/issues", + "Imports": [ + "utils" + ], + "Suggests": [ + "BiocManager", + "cli", + "compiler", + "covr", + "cpp11", + "curl", + "devtools", + "generics", + "gitcreds", + "jsonlite", + "jsonvalidate", + "knitr", + "miniUI", + "modules", + "packrat", + "pak", + "R6", + "remotes", + "reticulate", + "rmarkdown", + "rstudioapi", + "shiny", + "testthat", + "uuid", + "waldo", + "yaml", + "webfakes" + ], + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "VignetteBuilder": "knitr", + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Config/testthat/parallel": "true", + "Config/testthat/start-first": "bioconductor,python,install,restore,snapshot,retrieve,remotes", + "NeedsCompilation": "no", + "Author": "Kevin Ushey [aut, cre] (ORCID: ), Hadley Wickham [aut] (ORCID: ), Posit Software, PBC [cph, fnd]", + "Maintainer": "Kevin Ushey ", + "Repository": "RSPM" + }, + "reticulate": { + "Package": "reticulate", + "Version": "1.46.0", + "Source": "Repository", + "Type": "Package", + "Title": "Interface to 'Python'", + "Authors@R": "c( person(\"Tomasz\", \"Kalinowski\", role = c(\"ctb\", \"cre\"), email = \"tomasz@posit.co\"), person(\"Kevin\", \"Ushey\", role = c(\"aut\"), email = \"kevin@posit.co\"), person(\"JJ\", \"Allaire\", role = c(\"aut\"), email = \"jj@posit.co\"), person(\"RStudio\", role = c(\"cph\", \"fnd\")), person(\"Yuan\", \"Tang\", role = c(\"aut\", \"cph\"), email = \"terrytangyuan@gmail.com\", comment = c(ORCID = \"0000-0001-5243-233X\")), person(\"Dirk\", \"Eddelbuettel\", role = c(\"ctb\", \"cph\"), email = \"edd@debian.org\"), person(\"Bryan\", \"Lewis\", role = c(\"ctb\", \"cph\"), email = \"blewis@illposed.net\"), person(\"Sigrid\", \"Keydana\", role = c(\"ctb\"), email = \"sigrid@posit.co\"), person(\"Ryan\", \"Hafen\", role = c(\"ctb\", \"cph\"), email = \"rhafen@gmail.com\"), person(\"Marcus\", \"Geelnard\", role = c(\"ctb\", \"cph\"), comment = \"TinyThread library, http://tinythreadpp.bitsnbites.eu/\") )", + "Description": "Interface to 'Python' modules, classes, and functions. When calling into 'Python', R data types are automatically converted to their equivalent 'Python' types. When values are returned from 'Python' to R they are converted back to R types. Compatible with all versions of 'Python' >= 2.7.", + "License": "Apache License 2.0", + "URL": "https://rstudio.github.io/reticulate/, https://github.com/rstudio/reticulate", + "BugReports": "https://github.com/rstudio/reticulate/issues", + "SystemRequirements": "Python (>= 2.7.0)", + "Encoding": "UTF-8", + "Depends": [ + "R (>= 3.5)" + ], + "Imports": [ + "Matrix", + "Rcpp (>= 1.0.7)", + "RcppTOML", + "graphics", + "here", + "jsonlite", + "methods", + "png", + "rappdirs", + "utils", + "rlang", + "withr" + ], + "Suggests": [ + "callr", + "knitr", + "glue", + "cli", + "rmarkdown", + "pillar", + "testthat" + ], + "LinkingTo": [ + "Rcpp" + ], + "RoxygenNote": "7.3.3", + "VignetteBuilder": "knitr", + "Config/build/compilation-database": "true", + "NeedsCompilation": "yes", + "Author": "Tomasz Kalinowski [ctb, cre], Kevin Ushey [aut], JJ Allaire [aut], RStudio [cph, fnd], Yuan Tang [aut, cph] (ORCID: ), Dirk Eddelbuettel [ctb, cph], Bryan Lewis [ctb, cph], Sigrid Keydana [ctb], Ryan Hafen [ctb, cph], Marcus Geelnard [ctb, cph] (TinyThread library, http://tinythreadpp.bitsnbites.eu/)", + "Maintainer": "Tomasz Kalinowski ", + "Repository": "CRAN" + }, + "rlang": { + "Package": "rlang", + "Version": "1.2.0", + "Source": "Repository", + "Title": "Functions for Base Types and Core R and 'Tidyverse' Features", + "Description": "A toolbox for working with base types, core R features like the condition system, and core 'Tidyverse' features like tidy evaluation.", + "Authors@R": "c( person(\"Lionel\", \"Henry\", ,\"lionel@posit.co\", c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", ,\"hadley@posit.co\", \"aut\"), person(given = \"mikefc\", email = \"mikefc@coolbutuseless.com\", role = \"cph\", comment = \"Hash implementation based on Mike's xxhashlite\"), person(given = \"Yann\", family = \"Collet\", role = \"cph\", comment = \"Author of the embedded xxHash library\"), person(given = \"Posit, PBC\", role = c(\"cph\", \"fnd\")) )", + "License": "MIT + file LICENSE", + "ByteCompile": "true", + "Biarch": "true", + "Depends": [ + "R (>= 4.0.0)" + ], + "Imports": [ + "utils" + ], + "Suggests": [ + "cli (>= 3.1.0)", + "covr", + "crayon", + "desc", + "fs", + "glue", + "knitr", + "magrittr", + "methods", + "pillar", + "pkgload", + "rmarkdown", + "stats", + "testthat (>= 3.3.2)", + "tibble", + "usethis", + "vctrs (>= 0.2.3)", + "withr" + ], + "Enhances": [ + "winch" + ], + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "URL": "https://rlang.r-lib.org, https://github.com/r-lib/rlang", + "BugReports": "https://github.com/r-lib/rlang/issues", + "Config/build/compilation-database": "true", + "Config/testthat/edition": "3", + "Config/Needs/website": "dplyr, tidyverse/tidytemplate", + "NeedsCompilation": "yes", + "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut], mikefc [cph] (Hash implementation based on Mike's xxhashlite), Yann Collet [cph] (Author of the embedded xxHash library), Posit, PBC [cph, fnd]", + "Maintainer": "Lionel Henry ", + "Repository": "CRAN" + }, + "rmarkdown": { + "Package": "rmarkdown", + "Version": "2.31", + "Source": "Repository", + "Type": "Package", + "Title": "Dynamic Documents for R", + "Authors@R": "c( person(\"JJ\", \"Allaire\", , \"jj@posit.co\", role = \"aut\"), person(\"Yihui\", \"Xie\", , \"xie@yihui.name\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Jonathan\", \"McPherson\", , \"jonathan@posit.co\", role = \"aut\"), person(\"Javier\", \"Luraschi\", role = \"aut\"), person(\"Kevin\", \"Ushey\", , \"kevin@posit.co\", role = \"aut\"), person(\"Aron\", \"Atkins\", , \"aron@posit.co\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Andrew\", \"Dunning\", role = \"ctb\", comment = c(ORCID = \"0000-0003-0464-5036\")), person(\"Atsushi\", \"Yasumoto\", role = c(\"ctb\", \"cph\"), comment = c(ORCID = \"0000-0002-8335-495X\", cph = \"Number sections Lua filter\")), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Carson\", \"Sievert\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Devon\", \"Ryan\", , \"dpryan79@gmail.com\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8549-0971\")), person(\"Frederik\", \"Aust\", , \"frederik.aust@uni-koeln.de\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4900-788X\")), person(\"Jeff\", \"Allen\", , \"jeff@posit.co\", role = \"ctb\"), person(\"JooYoung\", \"Seo\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4064-6012\")), person(\"Malcolm\", \"Barrett\", role = \"ctb\"), person(\"Rob\", \"Hyndman\", , \"Rob.Hyndman@monash.edu\", role = \"ctb\"), person(\"Romain\", \"Lesur\", role = \"ctb\"), person(\"Roy\", \"Storey\", role = \"ctb\"), person(\"Ruben\", \"Arslan\", , \"ruben.arslan@uni-goettingen.de\", role = \"ctb\"), person(\"Sergio\", \"Oller\", role = \"ctb\"), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"jQuery UI contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt\"), person(\"Mark\", \"Otto\", role = \"ctb\", comment = \"Bootstrap library\"), person(\"Jacob\", \"Thornton\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Alexander\", \"Farkas\", role = c(\"ctb\", \"cph\"), comment = \"html5shiv library\"), person(\"Scott\", \"Jehl\", role = c(\"ctb\", \"cph\"), comment = \"Respond.js library\"), person(\"Ivan\", \"Sagalaev\", role = c(\"ctb\", \"cph\"), comment = \"highlight.js library\"), person(\"Greg\", \"Franko\", role = c(\"ctb\", \"cph\"), comment = \"tocify library\"), person(\"John\", \"MacFarlane\", role = c(\"ctb\", \"cph\"), comment = \"Pandoc templates\"), person(, \"Google, Inc.\", role = c(\"ctb\", \"cph\"), comment = \"ioslides library\"), person(\"Dave\", \"Raggett\", role = \"ctb\", comment = \"slidy library\"), person(, \"W3C\", role = \"cph\", comment = \"slidy library\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome\"), person(\"Ben\", \"Sperry\", role = \"ctb\", comment = \"Ionicons\"), person(, \"Drifty\", role = \"cph\", comment = \"Ionicons\"), person(\"Aidan\", \"Lister\", role = c(\"ctb\", \"cph\"), comment = \"jQuery StickyTabs\"), person(\"Benct Philip\", \"Jonsson\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\"), person(\"Albert\", \"Krewinkel\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\") )", + "Description": "Convert R Markdown documents into a variety of formats.", + "License": "GPL-3", + "URL": "https://github.com/rstudio/rmarkdown, https://pkgs.rstudio.com/rmarkdown/", + "BugReports": "https://github.com/rstudio/rmarkdown/issues", + "Depends": [ + "R (>= 3.0)" + ], + "Imports": [ + "bslib (>= 0.2.5.1)", + "evaluate (>= 0.13)", + "fontawesome (>= 0.5.0)", + "htmltools (>= 0.5.1)", + "jquerylib", + "jsonlite", + "knitr (>= 1.43)", + "methods", + "tinytex (>= 0.31)", + "tools", + "utils", + "xfun (>= 0.36)", + "yaml (>= 2.1.19)" + ], + "Suggests": [ + "digest", + "dygraphs", + "fs", + "rsconnect", + "downlit (>= 0.4.0)", + "katex (>= 1.4.0)", + "sass (>= 0.4.0)", + "shiny (>= 1.6.0)", + "testthat (>= 3.0.3)", + "tibble", + "vctrs", + "cleanrmd", + "withr (>= 2.4.2)", + "xml2" + ], + "VignetteBuilder": "knitr", + "Config/Needs/website": "rstudio/quillt, pkgdown", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "SystemRequirements": "pandoc (>= 1.14) - http://pandoc.org", + "NeedsCompilation": "no", + "Author": "JJ Allaire [aut], Yihui Xie [aut, cre] (ORCID: ), Christophe Dervieux [aut] (ORCID: ), Jonathan McPherson [aut], Javier Luraschi [aut], Kevin Ushey [aut], Aron Atkins [aut], Hadley Wickham [aut], Joe Cheng [aut], Winston Chang [aut], Richard Iannone [aut] (ORCID: ), Andrew Dunning [ctb] (ORCID: ), Atsushi Yasumoto [ctb, cph] (ORCID: , cph: Number sections Lua filter), Barret Schloerke [ctb], Carson Sievert [ctb] (ORCID: ), Devon Ryan [ctb] (ORCID: ), Frederik Aust [ctb] (ORCID: ), Jeff Allen [ctb], JooYoung Seo [ctb] (ORCID: ), Malcolm Barrett [ctb], Rob Hyndman [ctb], Romain Lesur [ctb], Roy Storey [ctb], Ruben Arslan [ctb], Sergio Oller [ctb], Posit Software, PBC [cph, fnd], jQuery UI contributors [ctb, cph] (jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt), Mark Otto [ctb] (Bootstrap library), Jacob Thornton [ctb] (Bootstrap library), Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Alexander Farkas [ctb, cph] (html5shiv library), Scott Jehl [ctb, cph] (Respond.js library), Ivan Sagalaev [ctb, cph] (highlight.js library), Greg Franko [ctb, cph] (tocify library), John MacFarlane [ctb, cph] (Pandoc templates), Google, Inc. [ctb, cph] (ioslides library), Dave Raggett [ctb] (slidy library), W3C [cph] (slidy library), Dave Gandy [ctb, cph] (Font-Awesome), Ben Sperry [ctb] (Ionicons), Drifty [cph] (Ionicons), Aidan Lister [ctb, cph] (jQuery StickyTabs), Benct Philip Jonsson [ctb, cph] (pagebreak Lua filter), Albert Krewinkel [ctb, cph] (pagebreak Lua filter)", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "2.1.1", + "Source": "Repository", + "Title": "Finding Files in Project Subdirectories", + "Authors@R": "person(given = \"Kirill\", family = \"M\\u00fcller\", role = c(\"aut\", \"cre\"), email = \"kirill@cynkra.com\", comment = c(ORCID = \"0000-0002-1416-3412\"))", + "Description": "Robust, reliable and flexible paths to files below a project root. The 'root' of a project is defined as a directory that matches a certain criterion, e.g., it contains a certain regular file.", + "License": "MIT + file LICENSE", + "URL": "https://rprojroot.r-lib.org/, https://github.com/r-lib/rprojroot", + "BugReports": "https://github.com/r-lib/rprojroot/issues", + "Depends": [ + "R (>= 3.0.0)" + ], + "Suggests": [ + "covr", + "knitr", + "lifecycle", + "rlang", + "rmarkdown", + "testthat (>= 3.2.0)", + "withr" + ], + "VignetteBuilder": "knitr", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2.9000", + "Config/autostyle/scope": "line_breaks", + "Config/autostyle/strict": "true", + "Config/Needs/website": "tidyverse/tidytemplate", + "NeedsCompilation": "no", + "Author": "Kirill Müller [aut, cre] (ORCID: )", + "Maintainer": "Kirill Müller ", + "Repository": "CRAN" + }, + "sass": { + "Package": "sass", + "Version": "0.4.10", + "Source": "Repository", + "Type": "Package", + "Title": "Syntactically Awesome Style Sheets ('Sass')", + "Description": "An 'SCSS' compiler, powered by the 'LibSass' library. With this, R developers can use variables, inheritance, and functions to generate dynamic style sheets. The package uses the 'Sass CSS' extension language, which is stable, powerful, and CSS compatible.", + "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@rstudio.com\", \"aut\"), person(\"Timothy\", \"Mastny\", , \"tim.mastny@gmail.com\", \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Barret\", \"Schloerke\", , \"barret@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Carson\", \"Sievert\", , \"carson@rstudio.com\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Christophe\", \"Dervieux\", , \"cderv@rstudio.com\", c(\"ctb\"), comment = c(ORCID = \"0000-0003-4474-2498\")), person(family = \"RStudio\", role = c(\"cph\", \"fnd\")), person(family = \"Sass Open Source Foundation\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Greter\", \"Marcel\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Mifsud\", \"Michael\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Hampton\", \"Catlin\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Natalie\", \"Weizenbaum\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Chris\", \"Eppstein\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Adams\", \"Joseph\", role = c(\"ctb\", \"cph\"), comment = \"json.cpp\"), person(\"Trifunovic\", \"Nemanja\", role = c(\"ctb\", \"cph\"), comment = \"utf8.h\") )", + "License": "MIT + file LICENSE", + "URL": "https://rstudio.github.io/sass/, https://github.com/rstudio/sass", + "BugReports": "https://github.com/rstudio/sass/issues", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2", + "SystemRequirements": "GNU make", + "Imports": [ + "fs (>= 1.2.4)", + "rlang (>= 0.4.10)", + "htmltools (>= 0.5.1)", + "R6", + "rappdirs" + ], + "Suggests": [ + "testthat", + "knitr", + "rmarkdown", + "withr", + "shiny", + "curl" + ], + "VignetteBuilder": "knitr", + "Config/testthat/edition": "3", + "NeedsCompilation": "yes", + "Author": "Joe Cheng [aut], Timothy Mastny [aut], Richard Iannone [aut] (), Barret Schloerke [aut] (), Carson Sievert [aut, cre] (), Christophe Dervieux [ctb] (), RStudio [cph, fnd], Sass Open Source Foundation [ctb, cph] (LibSass library), Greter Marcel [ctb, cph] (LibSass library), Mifsud Michael [ctb, cph] (LibSass library), Hampton Catlin [ctb, cph] (LibSass library), Natalie Weizenbaum [ctb, cph] (LibSass library), Chris Eppstein [ctb, cph] (LibSass library), Adams Joseph [ctb, cph] (json.cpp), Trifunovic Nemanja [ctb, cph] (utf8.h)", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "shiny": { + "Package": "shiny", + "Version": "1.13.0", + "Source": "Repository", + "Type": "Package", + "Title": "Web Application Framework for R", + "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"JJ\", \"Allaire\", , \"jj@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Garrick\", \"Aden-Buie\", , \"garrick@adenbuie.com\", role = \"aut\", comment = c(ORCID = \"0000-0002-7111-0077\")), person(\"Yihui\", \"Xie\", , \"yihui@posit.co\", role = \"aut\"), person(\"Jeff\", \"Allen\", role = \"aut\"), person(\"Jonathan\", \"McPherson\", , \"jonathan@posit.co\", role = \"aut\"), person(\"Alan\", \"Dipert\", role = \"aut\"), person(\"Barbara\", \"Borges\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")), person(, \"jQuery Foundation\", role = \"cph\", comment = \"jQuery library and jQuery UI library\"), person(, \"jQuery contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt\"), person(, \"jQuery UI contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery UI library; authors listed in inst/www/shared/jqueryui/AUTHORS.txt\"), person(\"Mark\", \"Otto\", role = \"ctb\", comment = \"Bootstrap library\"), person(\"Jacob\", \"Thornton\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Prem Nawaz\", \"Khan\", role = \"ctb\", comment = \"Bootstrap accessibility plugin\"), person(\"Victor\", \"Tsaran\", role = \"ctb\", comment = \"Bootstrap accessibility plugin\"), person(\"Dennis\", \"Lembree\", role = \"ctb\", comment = \"Bootstrap accessibility plugin\"), person(\"Srinivasu\", \"Chakravarthula\", role = \"ctb\", comment = \"Bootstrap accessibility plugin\"), person(\"Cathy\", \"O'Connor\", role = \"ctb\", comment = \"Bootstrap accessibility plugin\"), person(, \"PayPal, Inc\", role = \"cph\", comment = \"Bootstrap accessibility plugin\"), person(\"Stefan\", \"Petre\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap-datepicker library\"), person(\"Andrew\", \"Rowls\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap-datepicker library\"), person(\"Brian\", \"Reavis\", role = c(\"ctb\", \"cph\"), comment = \"selectize.js library\"), person(\"Salmen\", \"Bejaoui\", role = c(\"ctb\", \"cph\"), comment = \"selectize-plugin-a11y library\"), person(\"Denis\", \"Ineshin\", role = c(\"ctb\", \"cph\"), comment = \"ion.rangeSlider library\"), person(\"Sami\", \"Samhuri\", role = c(\"ctb\", \"cph\"), comment = \"Javascript strftime library\"), person(, \"SpryMedia Limited\", role = c(\"ctb\", \"cph\"), comment = \"DataTables library\"), person(\"Ivan\", \"Sagalaev\", role = c(\"ctb\", \"cph\"), comment = \"highlight.js library\"), person(\"R Core Team\", role = c(\"ctb\", \"cph\"), comment = \"tar implementation from R\") )", + "Description": "Makes it incredibly easy to build interactive web applications with R. Automatic \"reactive\" binding between inputs and outputs and extensive prebuilt widgets make it possible to build beautiful, responsive, and powerful applications with minimal effort.", + "License": "MIT + file LICENSE", + "URL": "https://shiny.posit.co/, https://github.com/rstudio/shiny", + "BugReports": "https://github.com/rstudio/shiny/issues", + "Depends": [ + "methods", + "R (>= 3.1.2)" + ], + "Imports": [ + "bslib (>= 0.6.0)", + "cachem (>= 1.1.0)", + "cli", + "commonmark (>= 2.0.0)", + "fastmap (>= 1.1.1)", + "fontawesome (>= 0.4.0)", + "glue (>= 1.3.2)", + "grDevices", + "htmltools (>= 0.5.4)", + "httpuv (>= 1.5.2)", + "jsonlite (>= 0.9.16)", + "later (>= 1.0.0)", + "lifecycle (>= 0.2.0)", + "mime (>= 0.3)", + "otel", + "promises (>= 1.5.0)", + "R6 (>= 2.0)", + "rlang (>= 0.4.10)", + "sourcetools", + "tools", + "utils", + "withr", + "xtable" + ], + "Suggests": [ + "Cairo (>= 1.5-5)", + "coro (>= 1.1.0)", + "datasets", + "DT", + "dygraphs", + "future", + "ggplot2", + "knitr (>= 1.6)", + "magrittr", + "markdown", + "mirai", + "otelsdk (>= 0.2.0)", + "ragg", + "reactlog (>= 1.0.0)", + "rmarkdown", + "sass", + "showtext", + "testthat (>= 3.2.1)", + "watcher", + "yaml" + ], + "Config/Needs/check": "shinytest2", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "Collate": "'globals.R' 'app-state.R' 'app_template.R' 'bind-cache.R' 'bind-event.R' 'bookmark-state-local.R' 'bookmark-state.R' 'bootstrap-deprecated.R' 'bootstrap-layout.R' 'conditions.R' 'map.R' 'utils.R' 'bootstrap.R' 'busy-indicators-spinners.R' 'busy-indicators.R' 'cache-utils.R' 'deprecated.R' 'devmode.R' 'diagnose.R' 'extended-task.R' 'fileupload.R' 'graph.R' 'reactives.R' 'reactive-domains.R' 'history.R' 'hooks.R' 'html-deps.R' 'image-interact-opts.R' 'image-interact.R' 'imageutils.R' 'input-action.R' 'input-checkbox.R' 'input-checkboxgroup.R' 'input-date.R' 'input-daterange.R' 'input-file.R' 'input-numeric.R' 'input-password.R' 'input-radiobuttons.R' 'input-select.R' 'input-slider.R' 'input-submit.R' 'input-text.R' 'input-textarea.R' 'input-utils.R' 'insert-tab.R' 'insert-ui.R' 'jqueryui.R' 'knitr.R' 'middleware-shiny.R' 'middleware.R' 'timer.R' 'shiny.R' 'mock-session.R' 'modal.R' 'modules.R' 'notifications.R' 'otel-attr-srcref.R' 'otel-collect.R' 'otel-enable.R' 'otel-error.R' 'otel-label.R' 'otel-reactive-update.R' 'otel-session.R' 'otel-shiny.R' 'otel-with.R' 'priorityqueue.R' 'progress.R' 'react.R' 'reexports.R' 'render-cached-plot.R' 'render-plot.R' 'render-table.R' 'run-url.R' 'runapp.R' 'serializers.R' 'server-input-handlers.R' 'server-resource-paths.R' 'server.R' 'shiny-options.R' 'shiny-package.R' 'shinyapp.R' 'shinyui.R' 'shinywrappers.R' 'showcase.R' 'snapshot.R' 'staticimports.R' 'tar.R' 'test-export.R' 'test-server.R' 'test.R' 'update-input.R' 'utils-lang.R' 'utils-tags.R' 'version_bs_date_picker.R' 'version_ion_range_slider.R' 'version_jquery.R' 'version_jqueryui.R' 'version_selectize.R' 'version_strftime.R' 'viewer.R'", + "NeedsCompilation": "no", + "Author": "Winston Chang [aut] (ORCID: ), Joe Cheng [aut], JJ Allaire [aut], Carson Sievert [aut, cre] (ORCID: ), Barret Schloerke [aut] (ORCID: ), Garrick Aden-Buie [aut] (ORCID: ), Yihui Xie [aut], Jeff Allen [aut], Jonathan McPherson [aut], Alan Dipert [aut], Barbara Borges [aut], Posit Software, PBC [cph, fnd] (ROR: ), jQuery Foundation [cph] (jQuery library and jQuery UI library), jQuery contributors [ctb, cph] (jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt), jQuery UI contributors [ctb, cph] (jQuery UI library; authors listed in inst/www/shared/jqueryui/AUTHORS.txt), Mark Otto [ctb] (Bootstrap library), Jacob Thornton [ctb] (Bootstrap library), Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Prem Nawaz Khan [ctb] (Bootstrap accessibility plugin), Victor Tsaran [ctb] (Bootstrap accessibility plugin), Dennis Lembree [ctb] (Bootstrap accessibility plugin), Srinivasu Chakravarthula [ctb] (Bootstrap accessibility plugin), Cathy O'Connor [ctb] (Bootstrap accessibility plugin), PayPal, Inc [cph] (Bootstrap accessibility plugin), Stefan Petre [ctb, cph] (Bootstrap-datepicker library), Andrew Rowls [ctb, cph] (Bootstrap-datepicker library), Brian Reavis [ctb, cph] (selectize.js library), Salmen Bejaoui [ctb, cph] (selectize-plugin-a11y library), Denis Ineshin [ctb, cph] (ion.rangeSlider library), Sami Samhuri [ctb, cph] (Javascript strftime library), SpryMedia Limited [ctb, cph] (DataTables library), Ivan Sagalaev [ctb, cph] (highlight.js library), R Core Team [ctb, cph] (tar implementation from R)", + "Maintainer": "Carson Sievert ", + "Repository": "CRAN" + }, + "sourcetools": { + "Package": "sourcetools", + "Version": "0.1.7-2", + "Source": "Repository", + "Type": "Package", + "Title": "Tools for Reading, Tokenizing and Parsing R Code", + "Authors@R": "person(\"Kevin\", \"Ushey\", role = c(\"aut\", \"cre\"), email = \"kevinushey@gmail.com\")", + "Maintainer": "Kevin Ushey ", + "Description": "Tools for the reading and tokenization of R code. The 'sourcetools' package provides both an R and C++ interface for the tokenization of R code, and helpers for interacting with the tokenized representation of R code.", + "License": "MIT + file LICENSE", + "Depends": [ + "R (>= 3.0.2)" + ], + "Suggests": [ + "testthat" + ], + "RoxygenNote": "5.0.1", + "BugReports": "https://github.com/kevinushey/sourcetools/issues", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Kevin Ushey [aut, cre]", + "Repository": "CRAN" + }, + "tinytex": { + "Package": "tinytex", + "Version": "0.59", + "Source": "Repository", + "Type": "Package", + "Title": "Helper Functions to Install and Maintain TeX Live, and Compile LaTeX Documents", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\", \"cph\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(\"Christophe\", \"Dervieux\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Devon\", \"Ryan\", role = \"ctb\", email = \"dpryan79@gmail.com\", comment = c(ORCID = \"0000-0002-8549-0971\")), person(\"Ethan\", \"Heinzen\", role = \"ctb\"), person(\"Fernando\", \"Cagua\", role = \"ctb\"), person() )", + "Description": "Helper functions to install and maintain the 'LaTeX' distribution named 'TinyTeX' (), a lightweight, cross-platform, portable, and easy-to-maintain version of 'TeX Live'. This package also contains helper functions to compile 'LaTeX' documents, and install missing 'LaTeX' packages automatically.", + "Imports": [ + "xfun (>= 0.48)" + ], + "Suggests": [ + "testit", + "rstudioapi" + ], + "License": "MIT + file LICENSE", + "URL": "https://github.com/rstudio/tinytex", + "BugReports": "https://github.com/rstudio/tinytex/issues", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "NeedsCompilation": "no", + "Author": "Yihui Xie [aut, cre, cph] (ORCID: ), Posit Software, PBC [cph, fnd], Christophe Dervieux [ctb] (ORCID: ), Devon Ryan [ctb] (ORCID: ), Ethan Heinzen [ctb], Fernando Cagua [ctb]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "withr": { + "Package": "withr", + "Version": "3.0.2", + "Source": "Repository", + "Title": "Run Code 'With' Temporarily Modified Global State", + "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = c(\"aut\", \"cre\")), person(\"Kirill\", \"Müller\", , \"krlmlr+r@mailbox.org\", role = \"aut\"), person(\"Kevin\", \"Ushey\", , \"kevinushey@gmail.com\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Winston\", \"Chang\", role = \"aut\"), person(\"Jennifer\", \"Bryan\", role = \"ctb\"), person(\"Richard\", \"Cotton\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )", + "Description": "A set of functions to run code 'with' safely and temporarily modified global state. Many of these functions were originally a part of the 'devtools' package, this provides a simple package with limited dependencies to provide access to these functions.", + "License": "MIT + file LICENSE", + "URL": "https://withr.r-lib.org, https://github.com/r-lib/withr#readme", + "BugReports": "https://github.com/r-lib/withr/issues", + "Depends": [ + "R (>= 3.6.0)" + ], + "Imports": [ + "graphics", + "grDevices" + ], + "Suggests": [ + "callr", + "DBI", + "knitr", + "methods", + "rlang", + "rmarkdown (>= 2.12)", + "RSQLite", + "testthat (>= 3.0.0)" + ], + "VignetteBuilder": "knitr", + "Config/Needs/website": "tidyverse/tidytemplate", + "Config/testthat/edition": "3", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.2", + "Collate": "'aaa.R' 'collate.R' 'connection.R' 'db.R' 'defer-exit.R' 'standalone-defer.R' 'defer.R' 'devices.R' 'local_.R' 'with_.R' 'dir.R' 'env.R' 'file.R' 'language.R' 'libpaths.R' 'locale.R' 'makevars.R' 'namespace.R' 'options.R' 'par.R' 'path.R' 'rng.R' 'seed.R' 'wrap.R' 'sink.R' 'tempfile.R' 'timezone.R' 'torture.R' 'utils.R' 'with.R'", + "NeedsCompilation": "no", + "Author": "Jim Hester [aut], Lionel Henry [aut, cre], Kirill Müller [aut], Kevin Ushey [aut], Hadley Wickham [aut], Winston Chang [aut], Jennifer Bryan [ctb], Richard Cotton [ctb], Posit Software, PBC [cph, fnd]", + "Maintainer": "Lionel Henry ", + "Repository": "CRAN" + }, + "xfun": { + "Package": "xfun", + "Version": "0.58", + "Source": "Repository", + "Type": "Package", + "Title": "Supporting Functions for Packages Maintained by 'Yihui Xie'", + "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\", \"cph\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Wush\", \"Wu\", role = \"ctb\"), person(\"Daijiang\", \"Li\", role = \"ctb\"), person(\"Xianying\", \"Tan\", role = \"ctb\"), person(\"Salim\", \"Brüggemann\", role = \"ctb\", email = \"salim-b@pm.me\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Christophe\", \"Dervieux\", role = \"ctb\"), person() )", + "Description": "Miscellaneous functions commonly used in other packages maintained by 'Yihui Xie'.", + "Depends": [ + "R (>= 3.2.0)" + ], + "Imports": [ + "grDevices", + "stats", + "tools" + ], + "Suggests": [ + "testit", + "parallel", + "codetools", + "methods", + "rstudioapi", + "tinytex (>= 0.30)", + "mime", + "litedown (>= 0.6)", + "commonmark", + "knitr (>= 1.50)", + "remotes", + "pak", + "curl", + "xml2", + "jsonlite", + "magick", + "yaml", + "data.table", + "qs2" + ], + "License": "MIT + file LICENSE", + "URL": "https://github.com/yihui/xfun", + "BugReports": "https://github.com/yihui/xfun/issues", + "Encoding": "UTF-8", + "VignetteBuilder": "litedown", + "Config/roxygen2/version": "8.0.0", + "NeedsCompilation": "yes", + "Author": "Yihui Xie [aut, cre, cph] (ORCID: , URL: https://yihui.org), Wush Wu [ctb], Daijiang Li [ctb], Xianying Tan [ctb], Salim Brüggemann [ctb] (ORCID: ), Christophe Dervieux [ctb]", + "Maintainer": "Yihui Xie ", + "Repository": "CRAN" + }, + "xtable": { + "Package": "xtable", + "Version": "1.8-8", + "Source": "Repository", + "Date": "2026-02-20", + "Title": "Export Tables to LaTeX or HTML", + "Authors@R": "c(person(\"David B.\", \"Dahl\", role=\"aut\"), person(\"David\", \"Scott\", role=c(\"aut\",\"cre\"), email=\"d.scott@auckland.ac.nz\"), person(\"Charles\", \"Roosen\", role=\"aut\"), person(\"Arni\", \"Magnusson\", role=\"aut\"), person(\"Jonathan\", \"Swinton\", role=\"aut\"), person(\"Ajay\", \"Shah\", role=\"ctb\"), person(\"Arne\", \"Henningsen\", role=\"ctb\"), person(\"Benno\", \"Puetz\", role=\"ctb\"), person(\"Bernhard\", \"Pfaff\", role=\"ctb\"), person(\"Claudio\", \"Agostinelli\", role=\"ctb\"), person(\"Claudius\", \"Loehnert\", role=\"ctb\"), person(\"David\", \"Mitchell\", role=\"ctb\"), person(\"David\", \"Whiting\", role=\"ctb\"), person(\"Fernando da\", \"Rosa\", role=\"ctb\"), person(\"Guido\", \"Gay\", role=\"ctb\"), person(\"Guido\", \"Schulz\", role=\"ctb\"), person(\"Ian\", \"Fellows\", role=\"ctb\"), person(\"Jeff\", \"Laake\", role=\"ctb\"), person(\"John\", \"Walker\", role=\"ctb\"), person(\"Jun\", \"Yan\", role=\"ctb\"), person(\"Liviu\", \"Andronic\", role=\"ctb\"), person(\"Markus\", \"Loecher\", role=\"ctb\"), person(\"Martin\", \"Gubri\", role=\"ctb\"), person(\"Matthieu\", \"Stigler\", role=\"ctb\"), person(\"Robert\", \"Castelo\", role=\"ctb\"), person(\"Seth\", \"Falcon\", role=\"ctb\"), person(\"Stefan\", \"Edwards\", role=\"ctb\"), person(\"Sven\", \"Garbade\", role=\"ctb\"), person(\"Uwe\", \"Ligges\", role=\"ctb\"))", + "Maintainer": "David Scott ", + "Imports": [ + "stats", + "utils", + "methods" + ], + "Suggests": [ + "knitr", + "zoo", + "survival", + "glue", + "tinytex" + ], + "VignetteBuilder": "knitr", + "Description": "Coerce data to LaTeX and HTML tables.", + "URL": "http://xtable.r-forge.r-project.org/", + "Depends": [ + "R (>= 2.10.0)" + ], + "License": "GPL (>= 2)", + "Repository": "CRAN", + "NeedsCompilation": "no", + "Author": "David B. Dahl [aut], David Scott [aut, cre], Charles Roosen [aut], Arni Magnusson [aut], Jonathan Swinton [aut], Ajay Shah [ctb], Arne Henningsen [ctb], Benno Puetz [ctb], Bernhard Pfaff [ctb], Claudio Agostinelli [ctb], Claudius Loehnert [ctb], David Mitchell [ctb], David Whiting [ctb], Fernando da Rosa [ctb], Guido Gay [ctb], Guido Schulz [ctb], Ian Fellows [ctb], Jeff Laake [ctb], John Walker [ctb], Jun Yan [ctb], Liviu Andronic [ctb], Markus Loecher [ctb], Martin Gubri [ctb], Matthieu Stigler [ctb], Robert Castelo [ctb], Seth Falcon [ctb], Stefan Edwards [ctb], Sven Garbade [ctb], Uwe Ligges [ctb]", + "Encoding": "UTF-8" + }, + "yaml": { + "Package": "yaml", + "Version": "2.3.12", + "Source": "Repository", + "Type": "Package", + "Title": "Methods to Convert R Data to YAML and Back", + "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"cre\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Shawn\", \"Garbett\", , \"shawn.garbett@vumc.org\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4079-5621\")), person(\"Jeremy\", \"Stephens\", role = c(\"aut\", \"ctb\")), person(\"Kirill\", \"Simonov\", role = \"aut\"), person(\"Yihui\", \"Xie\", role = \"ctb\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Zhuoer\", \"Dong\", role = \"ctb\"), person(\"Jeffrey\", \"Horner\", role = \"ctb\"), person(\"reikoch\", role = \"ctb\"), person(\"Will\", \"Beasley\", role = \"ctb\", comment = c(ORCID = \"0000-0002-5613-5006\")), person(\"Brendan\", \"O'Connor\", role = \"ctb\"), person(\"Michael\", \"Quinn\", role = \"ctb\"), person(\"Charlie\", \"Gao\", role = \"ctb\"), person(c(\"Gregory\", \"R.\"), \"Warnes\", role = \"ctb\"), person(c(\"Zhian\", \"N.\"), \"Kamvar\", role = \"ctb\") )", + "Description": "Implements the 'libyaml' 'YAML' 1.1 parser and emitter () for R.", + "License": "BSD_3_clause + file LICENSE", + "URL": "https://yaml.r-lib.org, https://github.com/r-lib/yaml/", + "BugReports": "https://github.com/r-lib/yaml/issues", + "Suggests": [ + "knitr", + "rmarkdown", + "testthat (>= 3.0.0)" + ], + "Config/testthat/edition": "3", + "Config/Needs/website": "tidyverse/tidytemplate", + "Encoding": "UTF-8", + "RoxygenNote": "7.3.3", + "VignetteBuilder": "knitr", + "NeedsCompilation": "yes", + "Author": "Hadley Wickham [cre] (ORCID: ), Shawn Garbett [ctb] (ORCID: ), Jeremy Stephens [aut, ctb], Kirill Simonov [aut], Yihui Xie [ctb] (ORCID: ), Zhuoer Dong [ctb], Jeffrey Horner [ctb], reikoch [ctb], Will Beasley [ctb] (ORCID: ), Brendan O'Connor [ctb], Michael Quinn [ctb], Charlie Gao [ctb], Gregory R. Warnes [ctb], Zhian N. Kamvar [ctb]", + "Maintainer": "Hadley Wickham ", + "Repository": "CRAN" + } + } +} diff --git a/renv/.gitignore b/renv/.gitignore new file mode 100644 index 0000000..0ec0cbb --- /dev/null +++ b/renv/.gitignore @@ -0,0 +1,7 @@ +library/ +local/ +cellar/ +lock/ +python/ +sandbox/ +staging/ diff --git a/renv/activate.R b/renv/activate.R new file mode 100644 index 0000000..20ffd44 --- /dev/null +++ b/renv/activate.R @@ -0,0 +1,1438 @@ + +local({ + + # the requested version of renv + version <- "1.2.3" + attr(version, "md5") <- "1bd9f58e1cfe27ce035933937c6f03de" + attr(version, "sha") <- NULL + + # the project directory + project <- Sys.getenv("RENV_PROJECT") + if (!nzchar(project)) + project <- getwd() + + # use start-up diagnostics if enabled + diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") + if (diagnostics) { + start <- Sys.time() + profile <- tempfile("renv-startup-", fileext = ".Rprof") + utils::Rprof(profile) + on.exit({ + utils::Rprof(NULL) + elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) + writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) + writeLines(sprintf("- Profile: %s", profile)) + print(utils::summaryRprof(profile)) + }, add = TRUE) + } + + # figure out whether the autoloader is enabled + enabled <- local({ + + # first, check config option + override <- getOption("renv.config.autoloader.enabled") + if (!is.null(override)) + return(override) + + # if we're being run in a context where R_LIBS is already set, + # don't load -- presumably we're being run as a sub-process and + # the parent process has already set up library paths for us + rcmd <- Sys.getenv("R_CMD", unset = NA) + rlibs <- Sys.getenv("R_LIBS", unset = NA) + if (!is.na(rlibs) && !is.na(rcmd)) + return(FALSE) + + # next, check environment variables + # prefer using the configuration one in the future + envvars <- c( + "RENV_CONFIG_AUTOLOADER_ENABLED", + "RENV_AUTOLOADER_ENABLED", + "RENV_ACTIVATE_PROJECT" + ) + + for (envvar in envvars) { + envval <- Sys.getenv(envvar, unset = NA) + if (!is.na(envval)) + return(tolower(envval) %in% c("true", "t", "1")) + } + + # enable by default + TRUE + + }) + + # bail if we're not enabled + if (!enabled) { + + # if we're not enabled, we might still need to manually load + # the user profile here + profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") + if (file.exists(profile)) { + cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") + if (tolower(cfg) %in% c("true", "t", "1")) + sys.source(profile, envir = globalenv()) + } + + return(FALSE) + + } + + # avoid recursion + if (identical(getOption("renv.autoloader.running"), TRUE)) { + warning("ignoring recursive attempt to run renv autoloader") + return(invisible(TRUE)) + } + + # signal that we're loading renv during R startup + options(renv.autoloader.running = TRUE) + on.exit(options(renv.autoloader.running = NULL), add = TRUE) + + # signal that we've consented to use renv + options(renv.consent = TRUE) + + # load the 'utils' package eagerly -- this ensures that renv shims, which + # mask 'utils' packages, will come first on the search path + library(utils, lib.loc = .Library) + + # unload renv if it's already been loaded + if ("renv" %in% loadedNamespaces()) + unloadNamespace("renv") + + # load bootstrap tools + ansify <- function(text) { + if (renv_ansify_enabled()) + renv_ansify_enhanced(text) + else + renv_ansify_default(text) + } + + renv_ansify_enabled <- function() { + + override <- Sys.getenv("RENV_ANSIFY_ENABLED", unset = NA) + if (!is.na(override)) + return(as.logical(override)) + + pane <- Sys.getenv("RSTUDIO_CHILD_PROCESS_PANE", unset = NA) + if (identical(pane, "build")) + return(FALSE) + + testthat <- Sys.getenv("TESTTHAT", unset = "false") + if (tolower(testthat) %in% "true") + return(FALSE) + + iderun <- Sys.getenv("R_CLI_HAS_HYPERLINK_IDE_RUN", unset = "false") + if (tolower(iderun) %in% "false") + return(FALSE) + + TRUE + + } + + renv_ansify_default <- function(text) { + text + } + + renv_ansify_enhanced <- function(text) { + + # R help links + pattern <- "`\\?(renv::(?:[^`])+)`" + replacement <- "`\033]8;;x-r-help:\\1\a?\\1\033]8;;\a`" + text <- gsub(pattern, replacement, text, perl = TRUE) + + # runnable code + pattern <- "`(renv::(?:[^`])+)`" + replacement <- "`\033]8;;x-r-run:\\1\a\\1\033]8;;\a`" + text <- gsub(pattern, replacement, text, perl = TRUE) + + # return ansified text + text + + } + + renv_ansify_init <- function() { + + envir <- renv_envir_self() + if (renv_ansify_enabled()) + assign("ansify", renv_ansify_enhanced, envir = envir) + else + assign("ansify", renv_ansify_default, envir = envir) + + } + + `%||%` <- function(x, y) { + if (is.null(x)) y else x + } + + catf <- function(fmt, ..., appendLF = TRUE) { + + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) + if (quiet) + return(invisible()) + + # also check for config environment variables that should suppress messages + # https://github.com/rstudio/renv/issues/2214 + enabled <- Sys.getenv("RENV_CONFIG_STARTUP_QUIET", unset = NA) + if (!is.na(enabled) && tolower(enabled) %in% c("true", "1")) + return(invisible()) + + enabled <- Sys.getenv("RENV_CONFIG_SYNCHRONIZED_CHECK", unset = NA) + if (!is.na(enabled) && tolower(enabled) %in% c("false", "0")) + return(invisible()) + + msg <- sprintf(fmt, ...) + cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") + + invisible(msg) + + } + + header <- function(label, + ..., + prefix = "#", + suffix = "-", + n = min(getOption("width"), 78)) + { + label <- sprintf(label, ...) + n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) + if (n <= 0) + return(paste(prefix, label)) + + tail <- paste(rep.int(suffix, n), collapse = "") + paste0(prefix, " ", label, " ", tail) + + } + + heredoc <- function(text, leave = 0) { + + # remove leading, trailing whitespace + trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) + + # split into lines + lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] + + # compute common indent + indent <- regexpr("[^[:space:]]", lines) + common <- min(setdiff(indent, -1L)) - leave + text <- paste(substring(lines, common), collapse = "\n") + + # substitute in ANSI links for executable renv code + ansify(text) + + } + + bootstrap <- function(version, library) { + + friendly <- renv_bootstrap_version_friendly(version) + section <- header(sprintf("Bootstrapping renv %s", friendly)) + catf(section) + + # ensure the target library path exists; required for file.copy(..., recursive = TRUE) + dir.create(library, showWarnings = FALSE, recursive = TRUE) + + # try to install renv from cache + md5 <- attr(version, "md5", exact = TRUE) + if (length(md5)) { + pkgpath <- renv_bootstrap_find(version) + if (length(pkgpath) && file.exists(pkgpath)) { + ok <- file.copy(pkgpath, library, recursive = TRUE) + if (isTRUE(ok)) + return(invisible()) + } + } + + # attempt to download renv + catf("- Downloading renv ... ", appendLF = FALSE) + withCallingHandlers( + tarball <- renv_bootstrap_download(version), + error = function(err) { + catf("FAILED") + stop("failed to download:\n", conditionMessage(err)) + } + ) + catf("OK") + on.exit(unlink(tarball), add = TRUE) + + # now attempt to install + catf("- Installing renv ... ", appendLF = FALSE) + withCallingHandlers( + status <- renv_bootstrap_install(version, tarball, library), + error = function(err) { + catf("FAILED") + stop("failed to install:\n", conditionMessage(err)) + } + ) + catf("OK") + + # add empty line to break up bootstrapping from normal output + catf("") + return(invisible()) + } + + renv_bootstrap_tests_running <- function() { + getOption("renv.tests.running", default = FALSE) + } + + renv_bootstrap_repos <- function() { + + # get CRAN repository + cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") + + # check for repos override + repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) + if (!is.na(repos)) { + + # split on ';' if present + parts <- strsplit(repos, ";", fixed = TRUE)[[1L]] + + # split into named repositories if present + idx <- regexpr("=", parts, fixed = TRUE) + keys <- substring(parts, 1L, idx - 1L) + vals <- substring(parts, idx + 1L) + names(vals) <- keys + + # if we have a single unnamed repository, call it CRAN + if (length(vals) == 1L && identical(keys, "")) + names(vals) <- "CRAN" + + return(vals) + + } + + # check for lockfile repositories + repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) + if (!inherits(repos, "error") && length(repos)) + return(repos) + + # retrieve current repos + repos <- getOption("repos") + + # ensure @CRAN@ entries are resolved + repos[repos == "@CRAN@"] <- cran + + # add in renv.bootstrap.repos if set + default <- c(FALLBACK = "https://cloud.r-project.org") + extra <- getOption("renv.bootstrap.repos", default = default) + repos <- c(repos, extra) + + # remove duplicates that might've snuck in + dupes <- duplicated(repos) | duplicated(names(repos)) + repos[!dupes] + + } + + renv_bootstrap_repos_lockfile <- function() { + + lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") + if (!file.exists(lockpath)) + return(NULL) + + lockfile <- tryCatch(renv_json_read(lockpath), error = identity) + if (inherits(lockfile, "error")) { + warning(lockfile) + return(NULL) + } + + repos <- lockfile$R$Repositories + if (length(repos) == 0) + return(NULL) + + keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) + vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) + names(vals) <- keys + + return(vals) + + } + + renv_bootstrap_download <- function(version) { + + sha <- attr(version, "sha", exact = TRUE) + + methods <- if (!is.null(sha)) { + + # attempting to bootstrap a development version of renv + c( + function() renv_bootstrap_download_tarball(sha), + function() renv_bootstrap_download_github(sha) + ) + + } else { + + # attempting to bootstrap a release version of renv + c( + function() renv_bootstrap_download_tarball(version), + function() renv_bootstrap_download_cran_latest(version), + function() renv_bootstrap_download_cran_archive(version) + ) + + } + + for (method in methods) { + path <- tryCatch(method(), error = identity) + if (is.character(path) && file.exists(path)) + return(path) + } + + stop("All download methods failed") + + } + + renv_bootstrap_download_impl <- function(url, destfile) { + + mode <- "wb" + + # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 + fixup <- + Sys.info()[["sysname"]] == "Windows" && + substring(url, 1L, 5L) == "file:" + + if (fixup) + mode <- "w+b" + + args <- list( + url = url, + destfile = destfile, + mode = mode, + quiet = TRUE + ) + + if ("headers" %in% names(formals(utils::download.file))) { + headers <- renv_bootstrap_download_custom_headers(url) + if (length(headers) && is.character(headers)) + args$headers <- headers + } + + do.call(utils::download.file, args) + + } + + renv_bootstrap_download_custom_headers <- function(url) { + + headers <- getOption("renv.download.headers") + if (is.null(headers)) + return(character()) + + if (!is.function(headers)) + stopf("'renv.download.headers' is not a function") + + headers <- headers(url) + if (length(headers) == 0L) + return(character()) + + if (is.list(headers)) + headers <- unlist(headers, recursive = FALSE, use.names = TRUE) + + ok <- + is.character(headers) && + is.character(names(headers)) && + all(nzchar(names(headers))) + + if (!ok) + stop("invocation of 'renv.download.headers' did not return a named character vector") + + headers + + } + + renv_bootstrap_download_cran_latest <- function(version) { + + spec <- renv_bootstrap_download_cran_latest_find(version) + type <- spec$type + repos <- spec$repos + + baseurl <- utils::contrib.url(repos = repos, type = type) + ext <- if (identical(type, "source")) + ".tar.gz" + else if (Sys.info()[["sysname"]] == "Windows") + ".zip" + else + ".tgz" + name <- sprintf("renv_%s%s", version, ext) + url <- paste(baseurl, name, sep = "/") + + destfile <- file.path(tempdir(), name) + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (inherits(status, "condition")) + return(FALSE) + + # report success and return + destfile + + } + + renv_bootstrap_download_cran_latest_find <- function(version) { + + # check whether binaries are supported on this system + binary <- + getOption("renv.bootstrap.binary", default = TRUE) && + !identical(.Platform$pkgType, "source") && + !identical(getOption("pkgType"), "source") && + Sys.info()[["sysname"]] %in% c("Darwin", "Windows") + + types <- c(if (binary) "binary", "source") + + # iterate over types + repositories + for (type in types) { + for (repos in renv_bootstrap_repos()) { + + # build arguments for utils::available.packages() call + args <- list(type = type, repos = repos) + + # add custom headers if available -- note that + # utils::available.packages() will pass this to download.file() + if ("headers" %in% names(formals(utils::download.file))) { + headers <- renv_bootstrap_download_custom_headers(repos) + if (length(headers) && is.character(headers)) + args$headers <- headers + } + + # retrieve package database + db <- tryCatch( + as.data.frame( + do.call(utils::available.packages, args), + stringsAsFactors = FALSE + ), + error = identity + ) + + if (inherits(db, "error")) + next + + # check for compatible entry + entry <- db[db$Package %in% "renv" & db$Version %in% version, ] + if (nrow(entry) == 0) + next + + # found it; return spec to caller + spec <- list(entry = entry, type = type, repos = repos) + return(spec) + + } + } + + # if we got here, we failed to find renv + fmt <- "renv %s is not available from your declared package repositories" + stop(sprintf(fmt, version)) + + } + + renv_bootstrap_download_cran_archive <- function(version) { + + name <- sprintf("renv_%s.tar.gz", version) + repos <- renv_bootstrap_repos() + urls <- file.path(repos, "src/contrib/Archive/renv", name) + destfile <- file.path(tempdir(), name) + + for (url in urls) { + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (identical(status, 0L)) + return(destfile) + + } + + return(FALSE) + + } + + renv_bootstrap_find <- function(version) { + + path <- renv_bootstrap_find_cache(version) + if (length(path) && file.exists(path)) { + catf("- Using renv %s from global package cache", version) + return(path) + } + + } + + renv_bootstrap_find_cache <- function(version) { + + md5 <- attr(version, "md5", exact = TRUE) + if (is.null(md5)) + return() + + # infer path to renv cache + cache <- Sys.getenv("RENV_PATHS_CACHE", unset = "") + if (!nzchar(cache)) { + root <- Sys.getenv("RENV_PATHS_ROOT", unset = NA) + if (!is.na(root)) + cache <- file.path(root, "cache") + } + + if (!nzchar(cache)) { + tools <- asNamespace("tools") + if (is.function(tools$R_user_dir)) { + root <- tools$R_user_dir("renv", "cache") + cache <- file.path(root, "cache") + } + } + + # start completing path to cache + file.path( + cache, + renv_bootstrap_cache_version(), + renv_bootstrap_platform_prefix(), + "renv", + version, + md5, + "renv" + ) + + } + + renv_bootstrap_download_tarball <- function(version) { + + # if the user has provided the path to a tarball via + # an environment variable, then use it + tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) + if (is.na(tarball)) + return() + + # allow directories + if (dir.exists(tarball)) { + name <- sprintf("renv_%s.tar.gz", version) + tarball <- file.path(tarball, name) + } + + # bail if it doesn't exist + if (!file.exists(tarball)) { + + # let the user know we weren't able to honour their request + fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." + msg <- sprintf(fmt, tarball) + warning(msg) + + # bail + return() + + } + + catf("- Using local tarball '%s'.", tarball) + tarball + + } + + renv_bootstrap_github_token <- function() { + for (envvar in c("GITHUB_TOKEN", "GITHUB_PAT", "GH_TOKEN")) { + envval <- Sys.getenv(envvar, unset = NA) + if (!is.na(envval)) + return(envval) + } + } + + renv_bootstrap_download_github <- function(version) { + + enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") + if (!identical(enabled, "TRUE")) + return(FALSE) + + # prepare download options + token <- renv_bootstrap_github_token() + if (is.null(token)) + token <- "" + + if (nzchar(Sys.which("curl")) && nzchar(token)) { + fmt <- "--location --fail --header \"Authorization: token %s\"" + extra <- sprintf(fmt, token) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "curl", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } else if (nzchar(Sys.which("wget")) && nzchar(token)) { + fmt <- "--header=\"Authorization: token %s\"" + extra <- sprintf(fmt, token) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "wget", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } + + url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) + name <- sprintf("renv_%s.tar.gz", version) + destfile <- file.path(tempdir(), name) + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (!identical(status, 0L)) + return(FALSE) + + renv_bootstrap_download_augment(destfile) + + return(destfile) + + } + + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we + # can use renv::install() to fully capture metadata. + renv_bootstrap_download_augment <- function(destfile) { + sha <- renv_bootstrap_git_extract_sha1_tar(destfile) + if (is.null(sha)) { + return() + } + + # Untar + tempdir <- tempfile("renv-github-") + on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) + untar(destfile, exdir = tempdir) + pkgdir <- dir(tempdir, full.names = TRUE)[[1]] + + # Modify description + desc_path <- file.path(pkgdir, "DESCRIPTION") + desc_lines <- readLines(desc_path) + remotes_fields <- c( + "RemoteType: github", + "RemoteHost: api.github.com", + "RemoteRepo: renv", + "RemoteUsername: rstudio", + "RemotePkgRef: rstudio/renv", + paste("RemoteRef: ", sha), + paste("RemoteSha: ", sha) + ) + writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) + + # Re-tar + local({ + old <- setwd(tempdir) + on.exit(setwd(old), add = TRUE) + + tar(destfile, compression = "gzip") + }) + invisible() + } + + # Extract the commit hash from a git archive. Git archives include the SHA1 + # hash as the comment field of the tarball pax extended header + # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) + # For GitHub archives this should be the first header after the default one + # (512 byte) header. + renv_bootstrap_git_extract_sha1_tar <- function(bundle) { + + # open the bundle for reading + # We use gzcon for everything because (from ?gzcon) + # > Reading from a connection which does not supply a 'gzip' magic + # > header is equivalent to reading from the original connection + conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) + on.exit(close(conn)) + + # The default pax header is 512 bytes long and the first pax extended header + # with the comment should be 51 bytes long + # `52 comment=` (11 chars) + 40 byte SHA1 hash + len <- 0x200 + 0x33 + res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) + + if (grepl("^52 comment=", res)) { + sub("52 comment=", "", res) + } else { + NULL + } + } + + renv_bootstrap_install <- function(version, tarball, library) { + + # attempt to install it into project library + dir.create(library, showWarnings = FALSE, recursive = TRUE) + output <- renv_bootstrap_install_impl(library, tarball) + + # check for successful install + status <- attr(output, "status") + if (is.null(status) || identical(status, 0L)) + return(status) + + # an error occurred; report it + header <- "installation of renv failed" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- paste(c(header, lines, output), collapse = "\n") + stop(text) + + } + + renv_bootstrap_install_impl <- function(library, tarball) { + + # invoke using system2 so we can capture and report output + bin <- R.home("bin") + exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" + R <- file.path(bin, exe) + + args <- c( + "--vanilla", "CMD", "INSTALL", "--no-multiarch", + "-l", shQuote(path.expand(library)), + shQuote(path.expand(tarball)) + ) + + system2(R, args, stdout = TRUE, stderr = TRUE) + + } + + renv_bootstrap_platform_prefix_default <- function() { + + # read version component + version <- Sys.getenv("RENV_PATHS_VERSION", unset = "R-%v") + + # expand placeholders + placeholders <- list( + list("%v", format(getRversion()[1, 1:2])), + list("%V", format(getRversion()[1, 1:3])) + ) + + for (placeholder in placeholders) + version <- gsub(placeholder[[1L]], placeholder[[2L]], version, fixed = TRUE) + + # include SVN revision for development versions of R + # (to avoid sharing platform-specific artefacts with released versions of R) + devel <- + identical(R.version[["status"]], "Under development (unstable)") || + identical(R.version[["nickname"]], "Unsuffered Consequences") + + if (devel) + version <- paste(version, R.version[["svn rev"]], sep = "-r") + + version + + } + + renv_bootstrap_platform_prefix <- function() { + + # construct version prefix + version <- renv_bootstrap_platform_prefix_default() + + # build list of path components + components <- c(version, R.version$platform) + + # include prefix if provided by user + prefix <- renv_bootstrap_platform_prefix_impl() + if (!is.na(prefix) && nzchar(prefix)) + components <- c(prefix, components) + + # build prefix + paste(components, collapse = "/") + + } + + renv_bootstrap_platform_prefix_impl <- function() { + + # if an explicit prefix has been supplied, use it + prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) + if (!is.na(prefix)) + return(prefix) + + # if the user has requested an automatic prefix, generate it + auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) + if (is.na(auto) && getRversion() >= "4.4.0") + auto <- "TRUE" + + if (auto %in% c("TRUE", "True", "true", "1")) + return(renv_bootstrap_platform_prefix_auto()) + + # empty string on failure + "" + + } + + renv_bootstrap_platform_prefix_auto <- function() { + + prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) + if (inherits(prefix, "error") || prefix %in% "unknown") { + + msg <- paste( + "failed to infer current operating system", + "please file a bug report at https://github.com/rstudio/renv/issues", + sep = "; " + ) + + warning(msg) + + } + + prefix + + } + + renv_bootstrap_platform_os <- function() { + + sysinfo <- Sys.info() + sysname <- sysinfo[["sysname"]] + + # handle Windows + macOS up front + if (sysname == "Windows") + return("windows") + else if (sysname == "Darwin") + return("macos") + + # check for os-release files + for (file in c("/etc/os-release", "/usr/lib/os-release")) + if (file.exists(file)) + return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) + + # check for redhat-release files + if (file.exists("/etc/redhat-release")) + return(renv_bootstrap_platform_os_via_redhat_release()) + + "unknown" + + } + + renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { + + # read /etc/os-release + release <- utils::read.table( + file = file, + sep = "=", + quote = c("\"", "'"), + col.names = c("Key", "Value"), + comment.char = "#", + stringsAsFactors = FALSE + ) + + vars <- as.list(release$Value) + names(vars) <- release$Key + + # get os name + os <- tolower(sysinfo[["sysname"]]) + + # read id + id <- "unknown" + for (field in c("ID", "ID_LIKE")) { + if (field %in% names(vars) && nzchar(vars[[field]])) { + id <- vars[[field]] + break + } + } + + # read version + version <- "unknown" + for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { + if (field %in% names(vars) && nzchar(vars[[field]])) { + version <- vars[[field]] + break + } + } + + # join together + paste(c(os, id, version), collapse = "-") + + } + + renv_bootstrap_platform_os_via_redhat_release <- function() { + + # read /etc/redhat-release + contents <- readLines("/etc/redhat-release", warn = FALSE) + + # infer id + id <- if (grepl("centos", contents, ignore.case = TRUE)) + "centos" + else if (grepl("redhat", contents, ignore.case = TRUE)) + "redhat" + else + "unknown" + + # try to find a version component (very hacky) + version <- "unknown" + + parts <- strsplit(contents, "[[:space:]]")[[1L]] + for (part in parts) { + + nv <- tryCatch(numeric_version(part), error = identity) + if (inherits(nv, "error")) + next + + version <- nv[1, 1] + break + + } + + paste(c("linux", id, version), collapse = "-") + + } + + renv_bootstrap_library_root_name <- function(project) { + + # use project name as-is if requested + asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") + if (asis) + return(basename(project)) + + # otherwise, disambiguate based on project's path + id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) + paste(basename(project), id, sep = "-") + + } + + renv_bootstrap_library_root <- function(project) { + + prefix <- renv_bootstrap_profile_prefix() + + path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) + if (!is.na(path)) + return(paste(c(path, prefix), collapse = "/")) + + path <- renv_bootstrap_library_root_impl(project) + if (!is.null(path)) { + name <- renv_bootstrap_library_root_name(project) + return(paste(c(path, prefix, name), collapse = "/")) + } + + renv_bootstrap_paths_renv("library", project = project) + + } + + renv_bootstrap_library_root_impl <- function(project) { + + root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) + if (!is.na(root)) + return(root) + + type <- renv_bootstrap_project_type(project) + if (identical(type, "package")) { + userdir <- renv_bootstrap_user_dir() + return(file.path(userdir, "library")) + } + + } + + renv_bootstrap_validate_version <- function(version, description = NULL) { + + # resolve description file + # + # avoid passing lib.loc to `packageDescription()` below, since R will + # use the loaded version of the package by default anyhow. note that + # this function should only be called after 'renv' is loaded + # https://github.com/rstudio/renv/issues/1625 + description <- description %||% packageDescription("renv") + + # check whether requested version 'version' matches loaded version of renv + sha <- attr(version, "sha", exact = TRUE) + valid <- if (!is.null(sha)) + renv_bootstrap_validate_version_dev(sha, description) + else + renv_bootstrap_validate_version_release(version, description) + + if (valid) + return(TRUE) + + # the loaded version of renv doesn't match the requested version; + # give the user instructions on how to proceed + dev <- identical(description[["RemoteType"]], "github") + remote <- if (dev) + paste("rstudio/renv", description[["RemoteSha"]], sep = "@") + else + paste("renv", description[["Version"]], sep = "@") + + # display both loaded version + sha if available + friendly <- renv_bootstrap_version_friendly( + version = description[["Version"]], + sha = if (dev) description[["RemoteSha"]] + ) + + fmt <- heredoc(" + renv %1$s was loaded from project library, but this project is configured to use renv %2$s. + - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. + - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. + ") + catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) + + FALSE + + } + + renv_bootstrap_validate_version_dev <- function(version, description) { + + expected <- description[["RemoteSha"]] + if (!is.character(expected)) + return(FALSE) + + pattern <- sprintf("^\\Q%s\\E", version) + grepl(pattern, expected, perl = TRUE) + + } + + renv_bootstrap_validate_version_release <- function(version, description) { + expected <- description[["Version"]] + is.character(expected) && identical(c(expected), c(version)) + } + + renv_bootstrap_hash_text <- function(text) { + + hashfile <- tempfile("renv-hash-") + on.exit(unlink(hashfile), add = TRUE) + + writeLines(text, con = hashfile) + tools::md5sum(hashfile) + + } + + renv_bootstrap_load <- function(project, libpath, version) { + + # try to load renv from the project library + if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) + return(FALSE) + + # warn if the version of renv loaded does not match + renv_bootstrap_validate_version(version) + + # execute renv load hooks, if any + hooks <- getHook("renv::autoload") + for (hook in hooks) + if (is.function(hook)) + tryCatch(hook(), error = warnify) + + # load the project + renv::load(project) + + TRUE + + } + + renv_bootstrap_profile_load <- function(project) { + + # if RENV_PROFILE is already set, just use that + profile <- Sys.getenv("RENV_PROFILE", unset = NA) + if (!is.na(profile) && nzchar(profile)) + return(profile) + + # check for a profile file (nothing to do if it doesn't exist) + path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) + if (!file.exists(path)) + return(NULL) + + # read the profile, and set it if it exists + contents <- readLines(path, warn = FALSE) + if (length(contents) == 0L) + return(NULL) + + # set RENV_PROFILE + profile <- contents[[1L]] + if (!profile %in% c("", "default")) + Sys.setenv(RENV_PROFILE = profile) + + profile + + } + + renv_bootstrap_profile_prefix <- function() { + profile <- renv_bootstrap_profile_get() + if (!is.null(profile)) + return(file.path("profiles", profile, "renv")) + } + + renv_bootstrap_profile_get <- function() { + profile <- Sys.getenv("RENV_PROFILE", unset = "") + renv_bootstrap_profile_normalize(profile) + } + + renv_bootstrap_profile_set <- function(profile) { + profile <- renv_bootstrap_profile_normalize(profile) + if (is.null(profile)) + Sys.unsetenv("RENV_PROFILE") + else + Sys.setenv(RENV_PROFILE = profile) + } + + renv_bootstrap_profile_normalize <- function(profile) { + + if (is.null(profile) || profile %in% c("", "default")) + return(NULL) + + profile + + } + + renv_bootstrap_path_absolute <- function(path) { + + substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( + substr(path, 1L, 1L) %in% c(letters, LETTERS) && + substr(path, 2L, 3L) %in% c(":/", ":\\") + ) + + } + + renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { + renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") + root <- if (renv_bootstrap_path_absolute(renv)) NULL else project + prefix <- if (profile) renv_bootstrap_profile_prefix() + components <- c(root, renv, prefix, ...) + paste(components, collapse = "/") + } + + renv_bootstrap_project_type <- function(path) { + + descpath <- file.path(path, "DESCRIPTION") + if (!file.exists(descpath)) + return("unknown") + + desc <- tryCatch( + read.dcf(descpath, all = TRUE), + error = identity + ) + + if (inherits(desc, "error")) + return("unknown") + + type <- desc$Type + if (!is.null(type)) + return(tolower(type)) + + package <- desc$Package + if (!is.null(package)) + return("package") + + "unknown" + + } + + renv_bootstrap_user_dir <- function() { + dir <- renv_bootstrap_user_dir_impl() + path.expand(chartr("\\", "/", dir)) + } + + renv_bootstrap_user_dir_impl <- function() { + + # use local override if set + override <- getOption("renv.userdir.override") + if (!is.null(override)) + return(override) + + # use R_user_dir if available + tools <- asNamespace("tools") + if (is.function(tools$R_user_dir)) + return(tools$R_user_dir("renv", "cache")) + + # try using our own backfill for older versions of R + envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") + for (envvar in envvars) { + root <- Sys.getenv(envvar, unset = NA) + if (!is.na(root)) + return(file.path(root, "R/renv")) + } + + # use platform-specific default fallbacks + if (Sys.info()[["sysname"]] == "Windows") + file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") + else if (Sys.info()[["sysname"]] == "Darwin") + "~/Library/Caches/org.R-project.R/R/renv" + else + "~/.cache/R/renv" + + } + + renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { + sha <- sha %||% attr(version, "sha", exact = TRUE) + parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) + paste(parts, collapse = "") + } + + renv_bootstrap_exec <- function(project, libpath, version) { + if (!renv_bootstrap_load(project, libpath, version)) + renv_bootstrap_run(project, libpath, version) + } + + renv_bootstrap_run <- function(project, libpath, version) { + tryCatch( + renv_bootstrap_run_impl(project, libpath, version), + error = function(e) { + msg <- paste( + "failed to bootstrap renv: the project will not be loaded.", + paste("Reason:", conditionMessage(e)), + "Use `renv::activate()` to re-initialize the project.", + sep = "\n" + ) + warning(msg, call. = FALSE) + } + ) + } + + renv_bootstrap_run_impl <- function(project, libpath, version) { + + # perform bootstrap + bootstrap(version, libpath) + + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + return(renv::load(project = project)) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + + } + + renv_bootstrap_cache_version <- function() { + # NOTE: users should normally not override the cache version; + # this is provided just to make testing easier + Sys.getenv("RENV_CACHE_VERSION", unset = "v5") + } + + renv_bootstrap_cache_version_previous <- function() { + version <- renv_bootstrap_cache_version() + number <- as.integer(substring(version, 2L)) + paste("v", number - 1L, sep = "") + } + + renv_json_read <- function(file = NULL, text = NULL) { + + jlerr <- NULL + + # if jsonlite is loaded, use that instead + if ("jsonlite" %in% loadedNamespaces()) { + + json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + jlerr <- json + + } + + # otherwise, fall back to the default JSON reader + json <- tryCatch(renv_json_read_default(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + # report an error + if (!is.null(jlerr)) + stop(jlerr) + else + stop(json) + + } + + renv_json_read_jsonlite <- function(file = NULL, text = NULL) { + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + jsonlite::fromJSON(txt = text, simplifyVector = FALSE) + } + + renv_json_read_patterns <- function() { + + list( + + # objects + list("{", "\t\n\tobject(\t\n\t", TRUE), + list("}", "\t\n\t)\t\n\t", TRUE), + + # arrays + list("[", "\t\n\tarray(\t\n\t", TRUE), + list("]", "\n\t\n)\n\t\n", TRUE), + + # maps + list(":", "\t\n\t=\t\n\t", TRUE), + + # newlines + list("\\u000a", "\n", FALSE) + + ) + + } + + renv_json_read_envir <- function() { + + envir <- new.env(parent = emptyenv()) + + envir[["+"]] <- `+` + envir[["-"]] <- `-` + + envir[["object"]] <- function(...) { + result <- list(...) + names(result) <- as.character(names(result)) + result + } + + envir[["array"]] <- list + + envir[["true"]] <- TRUE + envir[["false"]] <- FALSE + envir[["null"]] <- NULL + + envir + + } + + renv_json_read_remap <- function(object, patterns) { + + # repair names if necessary + if (!is.null(names(object))) { + + nms <- names(object) + for (pattern in patterns) + nms <- gsub(pattern[[2L]], pattern[[1L]], nms, fixed = TRUE) + names(object) <- nms + + } + + # repair strings if necessary + if (is.character(object)) { + for (pattern in patterns) + object <- gsub(pattern[[2L]], pattern[[1L]], object, fixed = TRUE) + } + + # recurse for other objects + if (is.recursive(object)) + for (i in seq_along(object)) + object[i] <- list(renv_json_read_remap(object[[i]], patterns)) + + # return remapped object + object + + } + + renv_json_read_default <- function(file = NULL, text = NULL) { + + # read json text + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + + # convert into something the R parser will understand + patterns <- renv_json_read_patterns() + transformed <- text + for (pattern in patterns) + transformed <- gsub(pattern[[1L]], pattern[[2L]], transformed, fixed = TRUE) + + # parse it + rfile <- tempfile("renv-json-", fileext = ".R") + on.exit(unlink(rfile), add = TRUE) + writeLines(transformed, con = rfile) + json <- parse(rfile, keep.source = FALSE, srcfile = NULL)[[1L]] + + # evaluate in safe environment + result <- eval(json, envir = renv_json_read_envir()) + + # fix up strings if necessary -- do so only with reversible patterns + patterns <- Filter(function(pattern) pattern[[3L]], patterns) + renv_json_read_remap(result, patterns) + + } + + + # load the renv profile, if any + renv_bootstrap_profile_load(project) + + # construct path to library root + root <- renv_bootstrap_library_root(project) + + # construct library prefix for platform + prefix <- renv_bootstrap_platform_prefix() + + # construct full libpath + libpath <- file.path(root, prefix) + + # run bootstrap code + renv_bootstrap_exec(project, libpath, version) + + invisible() + +}) diff --git a/renv/settings.json b/renv/settings.json new file mode 100644 index 0000000..46f2f31 --- /dev/null +++ b/renv/settings.json @@ -0,0 +1,21 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [], + "lockfile.sanitize": true, + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.dev": false, + "snapshot.type": "implicit", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7e59311 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pandas==2.3.3 \ No newline at end of file