Intro to Shiny Modules

Introduction to shiny modules

Agenda

  • Introduction to shiny modules

  • Including reactivity in your module

Modules

A shiny module provides you with a way to encapsulate both:

  • UI logic
  • Render logic

This allows you to:

  1. Create re-usable components
  2. Abstract large parts of code into a separate unit

This is:

  • Great for working with teams of developers
  • Essential for large applications

Module example

Create a shiny module:

from shiny express import input, output, session, module

@module
def card_module(input, output, session, title, fn):
   with ui.card():
       ui.card_header(title)
       @render.plot
       def _plot_out():
           return fn()

Call the module like you call a function:

card_module('id', 'title', fn)

Look carefully at the definition and the call:

Important

  1. You don’t pass input, output or session to the module
  2. You pass an id that must be unique in the namespace
  3. And then you pass the other arguments

Create a shiny module:

@module
def card_module(input, output, session, title, fn):
  ...


Call the module like you call a function:

card_module('id1', 'title', fn)

Your turn: create a simple shiny module

Including reactivity in your module

Agenda

  • Introduction to shiny modules

  • Including reactivity in your module

Your turn: create a more complicated shiny module

Delaying reactivity with lambda functions

Define a module:

@module
def card_module(input, output, session, title, fn):
    with ui.card():
        ui.card_header(title)
        @render.plot
        def _plot_out():
            return fn()

Calling it like this throws an error:

card_module(
    "card_1", 
    "Distribution", 
    plots.temp_distribution(filtered_data())
)

Important

RuntimeError: No current reactive context

Explaining the no current reactive context error

Python performs eager evaluation.

This means that plots.temp_distribution() gets evaluated when the card_module is instantiated.

card_module(
    "card_1", 
    "Distribution", 
    plots.temp_distribution(filtered_data())
)

But you need to delay this evaluation until the shiny app needs to render the value.

Fixing the no current reactive context error

Python evaluation is eager.

But you can delay evaluation to be lazy using a lambda inline function:

card_module(
    "card_1", 
    "Distribution", 
    lambda: plots.temp_distribution(filtered_data())
)

Your turn: insert the shiny module into your weather