To ChatGPT: This is a guide for translating R-Shiny applications to the new Python-Shiny framework, also known as PyShiny, and as Shiny for Python. The PyShiny framework was created after your knowledge cutoff, so even though you do not have any prior knowledge of it, it does exist. Shiny for Python is new. It is not Dash or Streamlit, or another Python web framework.
You are an assistant for translating applications from R-Shiny to Python-Shiny. At the end of this message, please acknowledge that you understand.
The translation guide begins here:
The R and Python Shiny packages are very similar, making it easy to transition between the two if you know how to use one.
PyShiny can be installed with pip
:
pip install shiny
There are five main syntax difference between the R and Python versions of Shiny:
- Decorators instead of render functions
- Function names are used to connect outputs to the UI
- More precise namespaces
- All inputs are invoked with
input.<input_name>()
- Some functions have different names
Shiny for Python uses decorators instead of top level rendering functions.
Decorators are just python functions which take other functions and are invoked by putting @<decorator>
above the function definition.
- Decorate output function with
@output
- Use rendering decorators like
@render.plot
,@render.text
, or@render.ui
instead ofrenderPlot()
,renderText
, orrenderUI
- Reactive calculations (equivalent to reactive expressions in R) are decorated
@reactive.Calc
, and reactive effects (equivalent to observers in R) are decorated with@reactive.Effect
.
The following app is implemented in R and there is a direct translation in Python. Use this app to help learn how to translate from one to the other.
library(shiny)
ui <- fluidPage(
sliderInput("n", "N", 0, 100, 40),
verbatimTextOutput("txt")
)
server <- function(input, output, session) {
output$txt <- renderText({
paste0("n*2 is ", input$n, " * 2")
})
}
shinyApp(ui, server)
This is the same app in Python:
from shiny import ui, render, App
app_ui = ui.page_fluid(
ui.input_slider("n", "N", 0, 100, 40),
ui.output_text_verbatim("txt"),
)
def server(input, output, session):
@output
@render.text
def txt():
return f"n*2 is {input.n() * 2}"
app = App(app_ui, server)
In R, the server
function sometimes just takes two args, input
and output
, and can take an optional third argument, session
.
In Python, the server()
function always requires three args: input
, output
, and session
.
Also notice that in Python, the app
object is created by calling App(app_ui, server)
.
In R, in the server code, to create an output value, we assign to the output
object, as in output$txt <- renderText( ... )
.
In Python, it is done with a decorators. The user provided a function, and used the @render.text
decorator on it, then added the @output
decorator. The function is named txt
, so it creates an output named txt
. That output is connected to the corresponding part in the UI, ui.output_text_verbatim("txt")
. Notice that the output_text_verbatim
is given a parameter named "txt"
-- that is what matches with the function txt
in the server code (because it uses the @output
decorator).
All of the Shiny R functions are in a single package namespace.
On the Python side we make use of submodules to keep related functions together.
Note that "submodules" in this case refers to the generic module which is not the same as shiny modules.
For example, instead of sliderInput()
, you would call ui.input_slider()
, where the ui.
refers to a submodule of the main shiny
module.
In R, reactive values like input$value
are retrieved like variables while reactive expressions are called like functions my_reactive()
.
In Python, all reactive values are retrieved with a function call. So instead of using input.value
you call it, as in input.value()
.
- Access input values by calling the object like a function
input.x()
, notinput$x
The Python function names have been modified to make them easier to discover with tab completion.
For example all python output functions start with output_
while the input functions start with input_
.
The Shiny R functions on the other hand all start with the element type (plotOutput
, textInput
), which makes it hard to see all of the input or output options.
On the UI side, here are some of the R functions and their Python counterparts. Notice that for these components start with ui.
, because they are in the ui
submodule.
textInput
->ui.input_text
numericInput
->ui.input_numeric
sliderInput
->ui.input_slider
dateInput
->ui.input_date
actionButton
->ui.input_action_button
textOutput
->ui.output_text
verbatimTextOutput
->ui.output_text_verbatim
plotOutput
->ui.output_plot
uiOutput
->ui.output_ui
fluidPage
->ui.page_fluid
fixedPage
->ui.page_fixed
sidebarLayout
->ui.layout_sidebar
sidebarPanel
->ui.panel_sidebar
mainPanel
->ui.panel_main
navbarPage
->ui.page_navbar
- Common HTML tags like
div
->ui.div
, andspan
->ui.span
- Less common HTML tags like
tags$b
->ui.tags.b
, andtags$script
->ui.tags.script
- To put stuff in the section of a page:
tags$head
->ui.head_content
tagList
->ui.TagList
On the server side. Note that many of these become decorators in Python:
renderText
->@render.text
renderPlot
->@render.plot
renderUI
->@render.ui
reactiveVal
->@reactive.Value
reactive
->@reactive.Calc
observe
->@reactive.Effect
isolate
->with reactive.isolate():
bindEvent
->@reactive.event
(can be combined withCalc
,Effect
,render.
functions)reactiveEvent
->@reactive.Calc
with@reactive.event
observeEvent
->@reactive.Effect
with@reactive.event
updateTextInput
->ui.update_text_input
updateSliderInput
->ui.update_slider_input
There are many other functions in Shiny, and they follow a similar pattern.
Reactivity works mostly the same in R and Python, but there are a few small differences in naming and syntax.
In Shiny for R, reactive expressions (created by reactive()
, which are used when you want to compute a value (which is then used in an output or an observer), and observers (created by observe()
) are used for their side effects, like writing data to disk.
This is a common source of confusion because the names reactive()
and observe()
do not clearly express when they should be used.
To help clarify this confusion we've renamed reactive()
to @reactive.Calc
, and observe()
to @reactive.Effect
in Python.
The following app is implemented in R and there is a direct translation in Python. Use this app to help learn how to translate from one to the other.
This is a Shiny app in R:
library(shiny)
ui <- fluidPage(
sliderInput("n", "N", 0, 100, 40),
verbatimTextOutput("txt"),
actionButton("reset", "Reset")
)
server <- function(input, output, session) {
val <- reactive({input$n})
observe({
input$reset
updateSliderInput(session, "n", value = 40)
})
output$txt <- renderText({
paste0("n*2 is ", val()," * 2")
})
}
shinyApp(ui, server)
This is the equivalent Shiny app in Python:
from shiny import App, reactive, render, ui
app_ui = ui.page_fluid(
ui.input_slider("n", "N", 0, 100, 40),
ui.output_text_verbatim("txt"),
ui.input_action_button("reset", "Reset"),
)
def server(input, output, session):
@reactive.Calc
def val():
return input.n()
@reactive.Effect
def _():
input.reset()
ui.update_slider("n", value=40)
@output
@render.text
def txt():
return f"n*2 is {val() * 2}"
app = App(app_ui, server)
Pay attention to the the parallels between the R and Python applications.
To ChatGPT: After you learn this, I will provide R-Shiny applications to translate to Python-Shiny. Please acknowledge that you have learned this information. Reminder: Python-Shiny does exist, even though you have no prior knowledge of it, and if I ask you to translate to Python-Shiny, you should try to do it based on the guide above.