-
Notifications
You must be signed in to change notification settings - Fork 18
Description
I tried to migrate the intraocular lens power calculator I previously created along with some logo images from Shiny Server to Shinylive, which does not require a server, and attempted to configure it on GitHub:
Here is my main code:
yml:
project:
type: website
output-dir: _site
format:
html:
grid:
body-width: 1300px
theme: lumen
filters:
- shinylive
title: "Risk Stratification and IOL Power Calculation Tool for Marfan Syndrome Patients with Ectopia Lentis"
author: Xinshen
date: 2025/05/17
date-format: long
filters:
- shinylive
Next comes the main part of the calculator.
#| standalone: true
#| viewerHeight: 2000
library(bslib)
library(shiny)
library(gt)
library(tidyverse)
library(magick)
library(shinyjs)
library(DT)
library(ggplot2)
#####IOL power calculation
****************
# Define UI for application that draws a histogram
gender_female_male <- c("Female", "Male")
eye_side <- c("Right", "Left")
procedures <- c("MCTR", "CTR-CH", "SF-IOL")
ui <- page_fixed(
useShinyjs(),
tags$style( "
html, body {
max-width: 1300px;
margin: auto;
width: 100%;
}
"),
layout_columns(
col_widths = c(4, 8),
card(
full_screen = TRUE,
imageOutput("img1_ui",, inline = TRUE),
style = "margin-top: 10px; display: flex; justify-content: center; align-items: center;"
),
card_body(
HTML(
'<div style="text-align: justify; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0 15px;">
<p style="text-indent: 20px; font-size: 18px; line-height: 1.6;">
*****************
</p>
</div>'
)
)
)
,
card(
full_screen = TRUE,
card_body(
fluidRow(
column(4, textInput("name", label = span("Patient's name", class = "label custom-input"), value = "")),
column(4, dateInput("dob", label = span("Patient's birthday", class = "label custom-input"), value = "1993-12-22")),
column(4, selectInput("Gender", label = span("Patient's gender", class = "label custom-input"), gender_female_male))
),
fluidRow(
column(4, selectInput("eyeside", label = span("Laterality", class = "label custom-input"), eye_side)),
column(4, textInput("surger", label = span("Doctor's name", class = "label custom-input"), value = "")),
column(4, dateInput("Sob", label = span("Surgery date", class = "label custom-input"), value = "2025-5-15"))
),
fluidRow(
column(4, numericInput("AL", label = span("AL (mm)", class = "label custom-input"), value = "24.03", step = 0.01)),
column(4, numericInput("WTW", label = span("WTW (mm)", class = "label custom-input"), value = "12.32", step = 0.01)),
column(4, numericInput("APEX", label = span("APEX (µm)", class = "label custom-input"), value = "553",step = 1))
),
fluidRow(
column(4, numericInput("K1", label = span("K1 (D)", class = "label custom-input"), value = "41.21",step = 0.01)),
column(4, numericInput("K2", label = span("K2 (D)", class = "label custom-input"), value = "42.33",step = 0.01)),
column(4, numericInput("ref", label = span("Target refraction (D)", class = "label custom-input"), value = "-1",step = 0.01))
),
fluidRow(
column(4,offset = 2, selectInput("procedure",label = span( "Procedure", class = "label custom-input"),choices = c("MCTR", "CTR-CH",
"SF-IOL"))),
column(4, selectInput("IOL_type",label = span( "IOL", class = "label custom-input"),
choices = c("DCB00/ICB00/ZCB00", "SN60AT/SN60WF","Rayner 920H/970C"))
)
)))
,
card(
actionButton("cal", label = span("Extimate cluster and calculate IOL power",class = "label custom-input"), class = "btn-success",
icon = shiny::icon("calculator"))
),
tags$div(
id = "plot_div",
style = "display:none;",
layout_columns(
col_widths = c(4, 8),
card(
div(
style = "display: flex; justify-content: center; align-items: center; height: 100%;",
uiOutput("words_cluster")
)
),
card(
div(
style = "margin-top: 10px; display: flex; justify-content: center; align-items: center;",
imageOutput("PCO_sur", inline = TRUE)
)
)
)
),
tags$div(
style = "display: flex; justify-content: center; align-items: center; height: 100%;",
uiOutput("conditional_layout")
)
)
server <- function(input, output, session) {
rdata_file1 <- tempfile(fileext = ".png")
correct_url1 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/sup1.png"
download.file(correct_url1, destfile = rdata_file1, mode = "wb")
rdata_file2 <- tempfile(fileext = ".png")
correct_url2 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/Logo-Department.png"
download.file(correct_url2, destfile = rdata_file2, mode = "wb")
rdata_file3 <- tempfile(fileext = ".png")
correct_url3 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/sup2.png"
download.file(correct_url3, destfile = rdata_file3, mode = "wb")
observeEvent(input$procedure, {
if (input$procedure %in% c("MCTR", "CTR-CH")) {
# If the first input is A or B, update second input to D and E
updateSelectInput(session, "IOL_type", choices = c("DCB00/ICB00/ZCB00", "SN60AT/SN60WF"))
} else if (input$procedure == "SF-IOL") {
# If the first input is C, update second input to F
updateSelectInput(session, "IOL_type", choices = "Rayner 920H/970C")
}
})
observeEvent(input$cal, {
shinyjs::show(id = "plot_div")
})
calculateValues <- eventReactive(input$cal, {
if(input$Gender == "Female") {
gg <- 0
} else {
gg <- 1
}
today <- Sys.Date()
dob <- as.Date(input$dob)
surgery_date <- as.Date(input$Sob)
aa <- as.numeric(difftime(surgery_date, dob, units = "days")) / 365.25
ccrz <- 337.5/(2/(1/input$K1 + 1/input$K2))
# calculate
***********
******************
output$conditional_layout <- renderUI({
values <- calculateValues()
aa <- values$aa
clus <- values$clus
if (aa > 15 || clus %in% c("C", "D")) {
div(
style = "width: 100%; max-width: 1300px; margin: 0 auto;", # 外层容器最大1300px
card(
style = "width: 100%; max-width: 1300px; margin: 0 auto;", # card充满容器
fluidRow(
div(
style = "width: 600px; margin: 0 auto;", # 固定内容宽度600px
uiOutput("words")
)
),
fluidRow(
div(
style = "width: 600px; margin: 0 auto;", # 固定内容宽度600px
DTOutput("table")
)
)
)
)
} else {
div(
style = "width: 100%; max-width: 1300px; margin: 0 auto; margin-top: 20px;",
card(
fluidRow(
div(
style = "width: 600px; margin: 0 auto;",
uiOutput("words")
)
),
fluidRow(
column(
width = 6,
div(
style = "width: 550px;", # 表格区域固定宽度
DTOutput("table")
)
),
column(
width = 6,
imageOutput("cluster_image") # 动态显示图片
)
)
)
)
}
})
output$cluster_image <- renderImage({
list(
src = rdata_file3,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
output$words_cluster <- renderUI({
clus <- calculateValues()$clus
description <- switch(clus,
************************ )
HTML(description)
})
# PCO_sur 输出逻辑
output$PCO_sur <- -renderImage({
list(
src = rdata_file1,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
output$img1_ui <-renderImage({
list(
src = rdata_file2,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
}
shinyApp(ui = ui, server = server)
This Shiny app has successfully run and has been uploaded to the server (https://xinshen.shinyapps.io/MFS_EL_cluster/), so I believe this Shiny app is usable. However, when I rendered it, I found that the images could not load, and clicking the action button in Shinylive had no response.
I thought the issue was with the way I was loading the images, so I added a Shinylive instance. I found that the way I was loading the images is indeed feasible.
#| standalone: true
#| viewerHeight: 200
library(shiny)
library(ggplot2)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
actionButton("cal", "Estimate IOL Power"),
imageOutput("img1_ui"),
imageOutput("img2_ui"),
imageOutput("img3_ui"),
uiOutput("words")
)
server <- function(input, output, session) {
rdata_file1 <- tempfile(fileext = ".png")
correct_url1 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/sup1.png"
download.file(correct_url1, destfile = rdata_file1, mode = "wb")
rdata_file2 <- tempfile(fileext = ".png")
correct_url2 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/Logo-Department.png"
download.file(correct_url2, destfile = rdata_file2, mode = "wb")
rdata_file3 <- tempfile(fileext = ".png")
correct_url3 <- "https://raw.githubusercontent.com/XinshenFD/data-save/main/sup2.png"
download.file(correct_url3, destfile = rdata_file3, mode = "wb")
output$img1_ui <- renderImage({
list(
src = rdata_file1,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
output$img2_ui <- renderImage({
list(
src = rdata_file2,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
output$img3_ui <- renderImage({
list(
src = rdata_file3,
contentType = "image/png",
style = "width:100%; height:auto;"
)
}, deleteFile = FALSE)
observeEvent(input$cal, {
shinyjs::show("img1_ui")
output$words <- renderUI({
HTML("<b>Calculation completed!</b>")
})
})
}
shinyApp(ui = ui, server = server)
My complete qmd document is at: https/raw.githubusercontent.com/XinshenFD/website/refs/heads/main/index.qmd
I want to know whether it is Shinylive that cannot achieve my goal or if there is an issue with my code.
Thanks