Note that the server part doesn’t run line-by-line. It’s a reactive environment that will run the code when input changes.
Code only reacts when it needs to, which is why it’s called reactive programming.
This makes it hard to test your code. And it’s hard to understand what’s going on when you’re new to Shiny!
The hard part about Shiny
My personal top ways ways to get more insight into what’s going on:
Use print() statements to see when something is happening
Use browser() to stop the code and inspect the environment (just as you can do within functions, because that is literally what server is!)
print() example
server <-function(input, output) {# Reactive function to fetch data fred_indicator <-reactive({ data <-fredr(series_id = input$indicator,observation_start = start_date,observation_end = end_date)print(paste("Data fetched for indicator:", input$indicator)) # Debug statementprint(head(data)) # Print first few rows of the fetched data data })# Reactive function to filter data fred_data <-reactive({ data <-fred_indicator() |>filter(between(date, input$range[1], input$range[2]))print(paste("Data filtered for range:", input$range[1], "to", input$range[2])) # Debug statement data })# Plotting function output$lineChart <-renderPlot({ data <-fred_data()print("Plotting data") # Debug statement before plottingggplot(data, aes(x = date, y = value)) +geom_line(color ="navyblue") +labs(x ="", y =names(vars[which(vars == input$indicator)])) +theme_minimal() })}
print() example
server <-function(input, output) {# Reactive function to fetch data fred_indicator <-reactive({ data <-fredr(series_id = input$indicator,observation_start = start_date,observation_end = end_date)print(paste("Data fetched for indicator:", input$indicator)) # Debug statementprint(head(data)) # Print first few rows of the fetched data })# Reactive function to filter data fred_data <-reactive({ data <-fred_indicator() |>filter(between(date, input$range[1], input$range[2]))print(paste("Data filtered for range:", input$range[1], "to", input$range[2])) # Debug statement data })# Plotting function output$lineChart <-renderPlot({ data <-fred_data()print("Plotting data") # Debug statement before plottingggplot(data, aes(x = date, y = value)) +geom_line(color ="navyblue") +labs(x ="", y =names(vars[which(vars == input$indicator)])) +theme_minimal() })}
browser() example
server <-function(input, output) {# Reactive function to fetch data fred_indicator <-reactive({browser() # Initiate debugging herefredr(series_id = input$indicator,observation_start = start_date,observation_end = end_date) })# Reactive function to filter data fred_data <-reactive({browser() # Debugging point to inspect filtered datafred_indicator() |>filter(between(date, input$range[1], input$range[2])) })# Plotting function output$lineChart <-renderPlot({browser() # Inspect before plottingggplot(fred_data(), aes(x = date, y = value)) +geom_line(color ="navyblue") +labs(x ="", y =names(vars[which(vars == input$indicator)])) +theme_minimal() })}
Your Turn!
Take the toy app from this section or another one you have made
Try adding print() or browser() statements to see when things are happening
10:00
More App-Building Tips
Wrangle some “working data”
Start by selecting a manageable subset of data.
Focus on a few indicators for initial testing.
Expand data scope after validating app functionality.
Use separate files
Separate data wrangling and visualization into different R scripts or Quarto documents.
Employ glimpse() and View() to verify data structures.
Helps isolate and troubleshoot errors effectively.
Start building with comments and function calls
Use comments to outline what each code section should do.
Introduce function calls without arguments to build the structure.
This method helps in maintaining clarity and debugging.
Test your UI code separately from your server code
Test UI components like drop-downs and sliders without server-side logic.
Helps ensure that the UI layout functions as intended.
Use dummy server functions to isolate UI issues.
Ensure reactive data frames are called correctly
Use parentheses to call reactive data frames within server functions.
Essential for maintaining reactivity and accurate data handling.
Avoids common bugs related to reactive contexts.
Properly call input in server functions
Check that input variables are used correctly in server functions.
Accurate naming ensures the server reacts properly to UI changes.
Critical for dynamic app behavior and user interactions.
Consider nonstandard evaluation in ggplot
Use .data[[]] to handle user inputs within ggplot2 aesthetics.
Ensures dynamic plotting based on user-selected data.
Nonstandard evaluation simplifies coding but requires careful handling.
Understand what your code is doing
Maintain a clear concept of each part’s function within your code.
Regularly test and refine to ensure it meets your objectives.
Theoretical understanding aids in effective troubleshooting and innovation.