2 April 2025
inst/build_module/5_python/app_hist.py
inst/build_module/4_moduleServer/appHist.R
"hist" connects app_ui and app_server componentscamelCase vs Python under_score conventionsbootstrapPage vs Python ui.page_fluidshinyApp() vs Python App().run()library & function vs Python import & defgeyser/hist.py
R/histApp.R
Shiny kludge:
app.run() may fail due to busy portio.app_run(app) to find free portR/io.py
def app_run(app, host = "127.0.0.1", port = None):
import socket
import webbrowser
import nest_asyncio
# Fix runtime event issue.
nest_asyncio.apply()
# Find free port.
if port is None:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
port = s.getsockname()[1]
# Open URL and run app.
url = f"{host}:{port}"
webbrowser.open(url)
app.run(host=host, port=port)Web interfaces are tricky, and can lead to collisions from multiple runs.
RuntimeError: This event loop is already runningapp.run() runs the appgeyser/hist.py
from shiny import module, render, ui
@module.server
def hist_server(input, output, session):
@render.plot
def main_plot():
...
@render.ui
def output_bw_adjust():
...
@module.ui
def hist_input():
return ui.card(...)
@module.ui
def hist_output():
return ui.output_plot("main_plot")
@module.ui
def hist_ui():
return ui.output_ui("output_bw_adjust")R/histApp.R
histServer <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$main_plot <- renderPlot(...)
output$bw_adjust <- renderUI(...)}}
histInput <- function(id) {
ns <- NS(id)
tagList(selectInput(ns("n_breaks"), ...),
checkboxInput(ns("individual_obs"), ...),
checkboxInput(ns("density"), ...))}
histOutput <- function(id) {
ns <- NS(id)
plotOutput(ns("main_plot"), ...)}
histUI <- function(id) {
ns <- NS(id)
uiOutput(ns("bw_adjust"))}geyser/hist.py
@module.server
def hist_server(input, output, session):
@render.plot
def main_plot():
fig, ax = plt.subplots()
hist_data = np.histogram(duration, bins=int(input.n_breaks()), ...)
if input.individual_obs():
ax.plot(duration, np.zeros_like(duration), 'r|', markersize=10)
if input.density():
kde = gaussian_kde(duration, bw_method=input.bw_adjust())
ax.plot(x_grid, kde(x_grid), color='blue')
@render.ui
def output_bw_adjust():
if input.density():
return ui.input_slider("bw_adjust", ...)R/histApp.R
histServer <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$main_plot <- renderPlot({
hist(duration, breaks = as.numeric(input$n_breaks), ...)
if (input$individual_obs)
rug(duration)
if (input$density)
lines(density(duration, adjust = input$bw_adjust), col = "blue")})
output$bw_adjust <- renderUI({
if(input$density)
sliderInput(ns("bw_adjust"), ...)})
}individual_obs, n_breaks, density, bw_adjustmain_plot, bw_adjustgeyser/hist.py
R/histApp.R
histServer <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
sliderInput(ns("bw_adjust"), ...)})}
histInput <- function(id) {
ns <- NS(id)
tagList(selectInput(ns("n_breaks"), ...),
checkboxInput(ns("individual_obs"), ...),
checkboxInput(ns("density"), ...))}
histOutput <- function(id) {
ns <- NS(id)
plotOutput(ns("main_plot"), ...)}
histUI <- function(id) {
ns <- NS(id)
uiOutput(ns("bw_adjust"))}@module.server and @module.ui set up python module namespaceid, NS(id) and session$ns set up R module namespacens("xxx") uses shiny namespace in Rinst/connect_modules/app_pages.py
from shiny import App, ui
from geyser.hist import *
from geyser.gghist import *
from geyser.ggpoint import *
app_ui = ui.page_navbar(
ui.nav_panel("hist",
hist_input("hist"), hist_output("hist"), hist_ui("hist")),
ui.nav_panel("gghist",
gghist_input("gghist"), gghist_output("gghist"), gghist_ui("gghist")),
ui.nav_panel("ggpoint",
ggpoint_input("ggpoint"), ggpoint_output("ggpoint"), ggpoint_ui("ggpoint")))
def app_server(input, output, session):
hist_server("hist")
gghist_server("gghist")
ggpoint_server("ggpoint")
App(app_ui, app_server).run()inst/connect_modules/appPages.R
library(geyser)
appUI <- bslib::page_navbar(
bslib::nav_panel("hist",
histInput("hist"), histOutput("hist"), histUI("hist")),
bslib::nav_panel("gghist",
gghistInput("gghist"), gghistOutput("gghist"), gghistUI("gghist")),
bslib::nav_panel("ggpoint",
ggpointInput("ggpoint"), ggpointOutput("ggpoint"), ggpointUI("ggpoint")))
appServer <- function(input, output, session) {
histServer("hist")
gghistServer("gghist")
ggpointServer("ggpoint")}
shiny::shinyApp(appUI, appServer)hist, gghist, ggpoint UIs across nav pagesgeyser/rows.py
R/rowsApp.R
rows shiny modules organize details across modulesdatasets (top row)hist, gghist, ggpoint columnsgeyser/rows.py
from shiny import ui, module
from geyser.datasets import *
from geyser.hist import *
from geyser.gghist import *
from geyser.ggpoint import *
@module.ui
def rows_input():
return ui.row(
ui.column(6, datasets_input("datasets")),
ui.column(6, datasets_ui("datasets")))
@module.ui
def rows_ui():
return ui.row(
ui.column(4, ui.card(ui.panel_title("hist"),
hist_input("hist"), hist_output("hist"), hist_ui("hist"))),
ui.column(4, ui.card(ui.panel_title("gghist"),
gghist_input("gghist"), gghist_output("gghist"), gghist_ui("gghist"))),
ui.column(4, ui.card(ui.panel_title("ggpoint"),
ggpoint_input("ggpoint"), ggpoint_output("ggpoint"), ggpoint_ui("ggpoint"))))R/rowsApp.R
library(geyser)
rowsInput <- function(id) {
ns <- NS(id)
bslib::layout_columns(
datasetsInput(ns("datasets")),
datasetsUI(ns("datasets")))
rowsUI <- function(id) {
ns <- NS(id)
bslib::layout_columns(
bslib::card(bslib::card_header("hist"),
histInput(ns("hist")), histOutput(ns("hist")), histUI(ns("hist"))),
bslib::card(bslib::card_header("gghist"),
gghistInput(ns("gghist")), gghistOutput(ns("gghist")), gghistUI(ns("gghist"))),
bslib::card(bslib::card_header("ggpoint"),
ggpointInput(ns("ggpoint")), ggpointOutput(ns("ggpoint")), ggpointUI(ns("ggpoint"))))}geyser/rows.py
from geyser.datasets import *
from geyser.hist import *
from geyser.gghist import *
from geyser.ggpoint import *
@module.server
def rows_server(input, output, session):
dataset = datasets_server("datasets")
hist_server("hist", dataset)
gghist_server("gghist", dataset)
ggpoint_server("ggpoint", dataset)R/rowsApp.R
rows module calls 4 other modulesdatasets module determines dataset and columnsdataset data frame is input to other 3 modulesgeyser package from GitHub or local
pip install pip@git+https://github.com/byandell/geyserpip install ~/Documents/GitHub/geyserbash, the shiny run app_hist.py may not workreticulate can fail due to multithreading.## Column and ### Row layout