diff --git a/apps/problem-sets/1-getting-started/1.1-data-frame/README b/apps/problem-sets/1-getting-started/1.1-data-frame/README index 3d23dee..d9f78e5 100644 --- a/apps/problem-sets/1-getting-started/1.1-data-frame/README +++ b/apps/problem-sets/1-getting-started/1.1-data-frame/README @@ -1 +1 @@ -The app code is almost complete, but the server function is not connected to the UI element, modify the code so the application runs. \ No newline at end of file +The app code is almost complete, but the server function is not connected to the UI element. Modify the code so the data frame actually appears. \ No newline at end of file diff --git a/apps/problem-sets/1-getting-started/1.2-debug/README b/apps/problem-sets/1-getting-started/1.2-debug/README index 13a1889..69f9ad6 100644 --- a/apps/problem-sets/1-getting-started/1.2-debug/README +++ b/apps/problem-sets/1-getting-started/1.2-debug/README @@ -1 +1 @@ -Something is wrong with this app and the data frame isn't rendering, can you figure out what's missing? \ No newline at end of file +Something is wrong with this app and the data frame isn't rendering. Can you figure out what's missing? \ No newline at end of file diff --git a/apps/problem-sets/1-getting-started/1.3-debug/README b/apps/problem-sets/1-getting-started/1.3-debug/README index 13a1889..69f9ad6 100644 --- a/apps/problem-sets/1-getting-started/1.3-debug/README +++ b/apps/problem-sets/1-getting-started/1.3-debug/README @@ -1 +1 @@ -Something is wrong with this app and the data frame isn't rendering, can you figure out what's missing? \ No newline at end of file +Something is wrong with this app and the data frame isn't rendering. Can you figure out what's missing? \ No newline at end of file diff --git a/apps/problem-sets/1-getting-started/1.4-debug/README b/apps/problem-sets/1-getting-started/1.4-debug/README index 13a1889..69f9ad6 100644 --- a/apps/problem-sets/1-getting-started/1.4-debug/README +++ b/apps/problem-sets/1-getting-started/1.4-debug/README @@ -1 +1 @@ -Something is wrong with this app and the data frame isn't rendering, can you figure out what's missing? \ No newline at end of file +Something is wrong with this app and the data frame isn't rendering. Can you figure out what's missing? \ No newline at end of file diff --git a/apps/problem-sets/1-getting-started/1.5-debug/README b/apps/problem-sets/1-getting-started/1.5-debug/README index 13a1889..69f9ad6 100644 --- a/apps/problem-sets/1-getting-started/1.5-debug/README +++ b/apps/problem-sets/1-getting-started/1.5-debug/README @@ -1 +1 @@ -Something is wrong with this app and the data frame isn't rendering, can you figure out what's missing? \ No newline at end of file +Something is wrong with this app and the data frame isn't rendering. Can you figure out what's missing? \ No newline at end of file diff --git a/apps/problem-sets/1-getting-started/1.6-filter-input/README b/apps/problem-sets/1-getting-started/1.6-filter-input/README index 8d45565..71f94bd 100644 --- a/apps/problem-sets/1-getting-started/1.6-filter-input/README +++ b/apps/problem-sets/1-getting-started/1.6-filter-input/README @@ -1 +1 @@ -Add a slider input to the app, the minimum value should be 2000, the maximum value should be 8000 and the selected value should be 6000. \ No newline at end of file +Add a slider input to the app. The minimum value should be 2000, the maximum value should be 8000, and the initial value should be 6000. \ No newline at end of file diff --git a/index.qmd b/index.qmd index 067eb9d..acc84b0 100644 --- a/index.qmd +++ b/index.qmd @@ -4,8 +4,8 @@ title: "Shiny for Python Workshop" # Introduction -This is the workshop website for the Shiny for Python Workshop at the 2023 Posit Conference. -While most of these materials are designed to be used in conjunction with the workshop, they also stand alone as an educational resource. +This is the workshop website for the Shiny for Python Workshop at [posit::conf 2023](https://posit.co/conference/). +While most of these materials are designed to be used in conjunction with the workshop, they also stand alone as an educational resource. If you have questions or comments, please raise a Github issue, and if you would like to attend the in-person workshop, please [register today](https://reg.conf.posit.co/flow/posit/positconf23/attendee-portal/page/sessioncatalog?search=&search.sessiontype=1675316728702001wr6r). If you would like help hosting a Shiny for Python workshop of your own or would like to book a webinar, please contact us on [Discord](https://discord.gg/AQVJzG2bnN). @@ -13,9 +13,9 @@ If you would like help hosting a Shiny for Python workshop of your own or would # Background -This workshop is aimed at people who are somewhat familliar with doing data analysis in Python, but do not have much of a background in Shiny. If you are brand new to Python we recommend spending a bit of time familliarizing yourself with the following topics before the workshop: +This workshop is aimed at people who are somewhat familiar with doing data analysis in Python, but do not have much of a background in Shiny. If you are brand new to Python we recommend spending a bit of time familiarizing yourself with the following topics before the workshop: -- How to install python packages in a virtual environment +- How to install Python packages in a virtual environment - How to do basic data manipulation with pandas or polars - How to draw plots - How to clone a repository with git @@ -24,7 +24,7 @@ This workshop is aimed at people who are somewhat familliar with doing data anal There are two ways to work through the examples and exercises in this workshop. -## 1) Shinylive +## 1) In your web browser with Shinylive Shinylive allows you to run full-featured shiny apps in your browser, and includes a basic editor which is good enough to run examples. As a result you should be able to work through all of the examples in the workshop using just the browser without installing anything locally. @@ -37,12 +37,13 @@ While Shinylive is great, it likely isn't the environment you'll use to develop 2) Install the Shiny for Python [VS Code extension](https://marketplace.visualstudio.com/items?itemName=posit.shiny-python) 3) Clone the repository with `git clone https://github.com/rstudio/shiny-python-workshop-2023.git`, or alternately download the repository as a zip file: \ ![](images/git-download-button.png){width="287"} -4) Navigate to the project directory and create a new virtual environment with `python3 -m venv .vevn` +4) Navigate to the project directory and create a new virtual environment with `python3 -m venv .venv` 5) Set your python interpreter to the virtual environment with `CMD + SHIFT + P` \> `Select Interpreter` 6) Open a new terminal prompt, which should switch to `(.venv)` 7) Install the relevant packages with `pip install -r requirements.txt` All of the example apps are stored in the `/apps` directory. The examples are in `apps/examples` and the problem sets are in `apps/problem-sets`. -If you've installed the VS Code extention can run any of the apps by opening the `app.py` file and clicking the play button in the top right. -Alternately, run them from the command line with `shiny run --reload`. \ No newline at end of file +If you've installed the Shiny for Python VS Code extension, you can run any of the apps by opening the `app.py` file and clicking the play button in the top right. ([See screenshot](https://camo.githubusercontent.com/5d947e6dff7d74fd1cf221e79583105c42e4986ae673ce79733ce5edbfdcdda5/68747470733a2f2f7368696e792e7273747564696f2e636f6d2f70792f646f63732f6173736574732f7673636f64652e706e67)) + +Alternatively, run them from the command line with `shiny run --reload`. \ No newline at end of file diff --git a/slides/getting-started.qmd b/slides/getting-started.qmd index 70746be..f5e8554 100644 --- a/slides/getting-started.qmd +++ b/slides/getting-started.qmd @@ -35,27 +35,32 @@ from helpers import problem_tabs, include_shiny_folder - WiFi: - Network: **Posit Conf 2023** - Password: **conf2023** -- There are gender-neutral bathrooms located are among the Grand Suite Bathrooms. +- There are gender-neutral bathrooms located among the Grand Suite Bathrooms. - There are two meditation/prayer rooms: Grand Suite 2A and Grand Suite 2B. Open Sunday - Tuesday 7:30 a.m. - 7:00 p.m., Wednesday 8:00 a.m. - 6:00 p.m. - The lactation room is located in Grand Suite 1. Open Sunday - Tuesday 7:30 a.m. - 7:00 p.m., Wednesday 8:00 a.m. - 6:00 p.m. -- Don't photograph people with red lanyards +- Don't photograph people with red lanyards. - The Code of Conduct and COVID policies can be found at https://posit.co/code-of-conduct/. ::: ## Outline for the day -9:00-10:30 : Getting started with Shiny - -10:30-11:00: Coffee break - -11:00-12:30 : Reactivity - -12:30 - 13:30: Lunch - -13:30 - 14:00: UI Customization - -15:00 - 15:30: Coffee break - -15:30 - 17:00: Workflow best practices / Q&A +| Start | End | Title | +|-------|-------|-------------------------------| +| 9:00 | 10:30 | Getting started with Shiny | +| 10:30 | 11:00 | Coffee break | +| 11:00 | 12:30 | Reactivity | +| 12:30 | 1:30 | Lunch | +| 1:30 | 3:00 | UI Customization | +| 3:00 | 3:30 | Coffee break | +| 3:30 | 5:00 | Workflow best practices / Q&A | + +```{=html} + +``` ## Goals of Session 1 @@ -74,13 +79,13 @@ from helpers import problem_tabs, include_shiny_folder ## Exercises - All of the exercises and slides are running live on the [website](https://posit-dev.github.io/shiny-python-workshop-2023/) - You can do them on the website or open the apps in the `apps/problem-sets` folder -- If you need help put a red sticker on your laptop, when you're done put up a green sticker +- If you need help, put a red sticker on your laptop; when you're done, put up a green sticker ## Testing your setup -1) In a terminal type `shiny create my-app` +1) In a terminal, type `shiny create my-app` 2) Open `my-app/app.py` -3) Click the "run app" button in the top right of VS Code +3) Click the "Run app" button in the top right of VS Code ([screenshot](https://camo.githubusercontent.com/5d947e6dff7d74fd1cf221e79583105c42e4986ae673ce79733ce5edbfdcdda5/68747470733a2f2f7368696e792e7273747564696f2e636f6d2f70792f646f63732f6173736574732f7673636f64652e706e67)) 4) If your local setup doesn't work, switch to Posit Workbench and try again @@ -92,7 +97,7 @@ from helpers import problem_tabs, include_shiny_folder # | output: asis include_shiny_folder( - "apps/examples/0.0-penguins", components="viewer", viewer_height=500 + "apps/examples/0.0-penguins", components="viewer", viewer_height=700 ) ``` @@ -103,7 +108,7 @@ include_shiny_folder( - Efficient ## Why Shiny for Python? -- Shiny is designed to take you from prototype to product +- Shiny is designed to take you from prototype to production - Easy enough to use for prototypes - Efficient enough to handle complexity - Everything you need to build production quality apps @@ -181,11 +186,11 @@ app = App(app_ui, server) ## UI functions -- UI functions are in the `ui` sub-module +- UI functions are in the `ui` submodule - Inputs start with `ui.input_*()` and take an id, and options -- Outputs start with `ui.output_*()` and usually just take an ID +- Outputs start with `ui.output_*()` and usually just take an id - Other functions like `ui.h1()` or `ui.p()` add static HTML to the app -- We'll get to layout functions in session 3 +- We'll get to layout functions in Session 3 ## Your turn @@ -193,7 +198,7 @@ Go to [exercises/1-hello-world](../exercises/1-hello-world.html) or run `apps/pr ## Server function -- Every shiny app needs a `server` function +- Every Shiny app needs a `server` function - The server function executes for each user session - This function contains **rendering functions** which define how to turn inputs into outputs @@ -268,9 +273,9 @@ def server(input: Inputs, output: Outputs, session: Session): return f"n*2 is {input.n() * 2}" ``` -- Inputs are called `input.n()` not `input.n` -- Referring to an input creates a reactive link between the input and output -- When the input changes the rendering function will re-execute +- Inputs are read by calling them like a function: `input.n()`, not `input.n` +- The act of reading an input creates a reactive link between that input and the rendering function that's currently executing +- When the input changes, the rendering function will re-execute - You can use multiple inputs in the same rendering function ## Your turn @@ -279,13 +284,13 @@ Go to [exercises/3-add-filter](../exercises/3-add-filter.html) or work through e ## Recap -Most shiny app development consists of variations of these three things: +Most Shiny app development consists of variations of these three things: -1) Add ui elements +1) Add UI elements 1) Add rendering functions 1) Connect inputs and outputs ## Your turn -Go to [exercises/4-add-plot](../exercises/4-add-plot.html) or work through exercises 1.10 locally. +Go to [exercises/4-add-plot](../exercises/4-add-plot.html) or work through exercise 1.10 locally. diff --git a/slides/reactivity.qmd b/slides/reactivity.qmd index e2c2fe1..3e3067c 100644 --- a/slides/reactivity.qmd +++ b/slides/reactivity.qmd @@ -71,14 +71,15 @@ include_shiny_folder( ## Does that really work? - You're not wrong to find this suspicious -- Magic automatic rendering often goes badly wrong +- "Does Shiny infer relationships by analyizing the source code?" No--lots of ways that would break down! - For this to work, the inference has to be 100% reliable ## It really works -- We have 10 years of experience with this pattern -- R users have found the bugs and illuminated the edge cases -- Shiny will always infer the correct computation graph +- We have 10 years of real-world experience with this form of reactivity +- The underlying mechanism is simple, reliable, and intuitive +- Not static analysis, but rather, runtime tracing +- Originally inspired by Meteor.js ## Outputs and recipes @@ -140,7 +141,7 @@ flowchart TD ## Declarative programming -- Tell Shiny what you want to happen +- Tell Shiny how each output should be filled - Trust that the framework will keep everything up-to-date - You're setting the menu, not doing the cooking @@ -162,7 +163,7 @@ include_shiny_folder( file_name="app-solution.py", exclusions=["app.py"], components="viewer", - viewer_height=500, + viewer_height=600, ) ``` @@ -178,7 +179,7 @@ flowchart TD linkStyle 2 display:none ``` -## Calculate Scatter plot +## Calculate scatter plot ```{mermaid} flowchart TD @@ -407,7 +408,7 @@ TODO: Insert reactivity exercise here - Each input is passed to a rendering function which produces an output - Input -> Recipe -> Output can produce repetitive, inefficient applications - `@reactive.Calc` lets you define calculations which are consumed by downstream functions -- This adds intermediary nodes to the reactive graph +- This adds intermediate nodes to the reactive graph ## Reactive Calc example @@ -418,7 +419,7 @@ TODO: Insert reactivity exercise here include_shiny_folder("apps/examples/2.0-simple-reactive-calc") ``` -## Identify repition +## Identify repetition ```{.python code-line-numbers="4,5,11,12"} @output @render.table @@ -472,8 +473,11 @@ include_shiny_folder("apps/examples/2.0-simple-reactive-calc") ## Reactive calculations - Defined with the `@reactive.Calc` decorator - Called like other inputs -- Can consume inputs, reactive values, or other reactive calculations -- Adds a node to the reactive graph. +- Can read inputs, reactive values, or other reactive calculations +- Caches its value, so it's cheap to call repeatedly +- Adds a node to the reactive graph + - Discards cached value when upstream nodes invalidate + - Notifies downstream nodes when it invalidates ## Initial state ```{mermaid} @@ -536,7 +540,7 @@ flowchart TD linkStyle 2 display:none ``` -## Recalculate plot +## Calculate plot ```{mermaid} flowchart TD Sl[Slider] --> S[Sample] @@ -547,7 +551,7 @@ flowchart TD linkStyle 2 display:none ``` -## Recalculate plot +## Calculate plot ```{mermaid} flowchart TD Sl[Slider] --> S[Sample] @@ -700,15 +704,18 @@ flowchart TD ## Escaping reactivity -- By default any change in a shiny input will trigger a recalculation +- By default, any change in an input will trigger immediate recalculation in all outputs that use it - This isn't always the user interaction you want - Database queries - Expensive modeling - Grouping multiple filters together - Side effects -- `reactive.event` and `reactive.Effect` allow you to interrupt reactive calculations. +- Use `reactive.event` to explicitly specify what should trigger recalculation for an output or calc ## Example + +TODO: Shouldn't this be showing app-solution.py, not app.py? + ```{python} # | echo: false # | output: asis @@ -776,7 +783,7 @@ include_shiny_folder( ``` {.python} @reactive.Effect -2@reactive.event(input.show) +@reactive.event(input.show) def toggle_modal(): m = ui.modal( "This is a somewhat important message.",