= fluidPage(
ui tabsetPanel(
tabPanel("Questionnaire",
fluidRow(
br(),
column(12, "PHQ-9",
fluidRow(
column(5, "Questionnaire"),
column(7, "Scores")
))), fluidRow(
column(12, "",
fluidRow(
column(5, "Little interest or pleasure in doing things"),
column(7, radioButtons("phq1", "",
choiceNames = c('Not at all',
'Several',
'More than half',
'Nearly every'
), choiceValues = c(0,1, 2, 3),
inline = TRUE))
)
)), actionButton("submit_depression", "Submit!"),
htmlOutput("depression")
)
) )
7 Shiny for questionnaire of PHQ-9
In this chapter, I will discuss about the PHQ-9 and shiny apps.
PHQ-9
The Patient Health Questionnaire-9 (PHQ-9) is a self-report questionnaire used to screen for major depressive disorder (MDD). It is a nine-item questionnaire that asks about symptoms of depression such as depressed mood, loss of interest or pleasure, changes in sleep, changes in appetite, changes in energy, difficulty concentrating, worthlessness or excessive guilt, thoughts of death or suicide, and psychomotor agitation or retardation. The PHQ-9 is scored on a scale of 0 to 27, with higher scores indicating more severe depression. A score of 10 or more is considered to be positive for MDD.
for questionnaire, the url is following.
https://med.stanford.edu/fastlab/research/imapp/msrs/_jcr_content/main/accordion/accordion_content3/download_256324296/file.res/PHQ9%20id%20date%2008.03.pdf
Here are the guidelines for each score on the PHQ-9:
Score | severity | Guideline |
---|---|---|
0-4 | Minimal depression | You may have some mild symptoms of depression, but they are not severe enough to interfere with your daily life. |
5-9 | Mild depression | You may have some moderate symptoms of depression, and they may be interfering with your daily life to some extent. |
10-14 | Moderate depression | You may have some severe symptoms of depression, and they are interfering with your daily life to a significant extent. |
15-19 | Moderately severe depression | You may have some very severe symptoms of depression, and they are interfering with your daily life to a great extent. |
20-27 | Severe depression | You may have some extremely severe symptoms of depression, and they are interfering with your daily life to a very great extent. |
Let’s begin by creating a basic template for Shiny applications.
This template will serve as a foundation for us to build upon as we develop interactive web applications using the Shiny package in R. Our starting point will be the essential UI and server components, ensuring a seamless structure to organize our application’s functionality and presentation
ui = fluidPage(…): The ui object defines the user interface of the Shiny app. fluidPage is a layout function that creates a page with fluid layout. Fluid layout means that the layout of your page will adjust to the size of the browser window, so it’s responsive and works well on both desktops and mobile devices.
tabsetPanel(…): This function creates a tabbed panel in the user interface, allowing users to switch between different tabs within the application. It’s a good way to organize content that’s divided into different categories or sections.
tabPanel(“Questionnaire”): This is the first tab in the tabbed panel. It creates a tab with the title “Questionnaire”. The content of the tab (which is not shown in your snippet) would be defined within this tabPanel function.
tabPanel(“Results”): Similarly, this creates a second tab titled “Results”. This tab would typically be used to display the results of the questionnaire or any other outputs or visualizations that your app produces based on the user input.
Now, let’s creates a fluid page with a single tab panel containing a questionnaire based on the Patient Health Questionnaire-9 (PHQ-9)
- The radioButtons() function has the following arguments:
- phq1: The name of the radio button group.
- label: The label for the radio button group.
- choiceNames: A vector of strings that contains the names of the options in the radio button group.
- choiceValues: A vector of numbers that corresponds to the values of the options in the radio button group.
- inline: A logical value that indicates whether the radio buttons should be displayed inline (TRUE) or in a separate row (FALSE).
When this code is executed, it will create a radio button group with the following options:
choiceNames | choiceValues |
---|---|
Not at all | (0) |
Several | (1) |
More than half | (2) |
Nearly every | (3) |
The user can select one of these options by clicking on the corresponding radio button.
The value of the selected option will be stored in the variable phq1.
The depression_score() reactive function is defined as follows:
<- reactive({
depression_score = as.numeric(input$phq1)
phq1 return(sum(phq1))
})
This function first converts the value of the phq1 input to a number. It then sums the values of the phq1 input. The result is returned from the function.
= function(input, output, session){
server
observeEvent(input$submit_depression, {
<- reactive({
depression_score = as.numeric(input$phq1)
phq1 return(sum(phq1))
})$depression <- renderText({
outputpaste("Your Score is", depression_score(), "point")
})
}) }
The renderText() function is used to render text to the output. In the code you provided, the renderText() function is used to render the text “Your Score is” followed by the value of the depression_score() reactive function.
= fluidPage(
ui # previous UI code here
htmlOutput("depression")
)
finally for UI again, the htmlOutput() function is used to create an output that will display the value of the depression reactive function. The value of the depression reactive function is the depression score calculated based on the value of the phq1 input
Let’s make global.R
= c("shiny", "tidyverse")
pkgs
for (pkg in pkgs){
if(!require(pkg, character.only = T)){
install.packages(pkg)
library(pkg, character.only = T)
}
}
<-list("1) Little interest or pleasure in doing things?",
q_depression "2) Feeling down, depressed, or hopeless?",
"3) Trouble falling or staying asleep, or sleeping too much?",
"4) Feeling tired or having little energy?",
"5) Poor appetite or overeating?",
"6) Feeling bad about yourself or that you are a failure or
have let yourself or your family down?",
"7) Trouble concentrating on things, such as reading the
newspaper or watching television?",
"8) Moving or speaking so slowly that other people could
have noticed. Or the opposite being so figety or
restless that you have been moving around a lot more
than usual?",
"9) Thoughts that you would be better off dead, or of
hurting yourself")
<- c('Not at all',
bt_depression 'Several days',
'More than \nhalf the days',
'Nearly every day')
<- c(0,1,2,3) sc_depression
Now, I will use global, q_depression, bt_depression and sc_depression, to shorten the code of ui in Shiny.
= fluidPage(
ui tabsetPanel(
tabPanel("Questionnaire",
fluidRow(
br(),
column(12, "PHQ-9",
fluidRow(
column(5, "Questionnaire"),
column(7, "Scores")
))), fluidRow(
column(12, "",
fluidRow(
column(5, q_depression[[1]]),
column(7, radioButtons(sprintf("phq%s", 1), "",
choiceNames = bt_depression,
choiceValues = sc_depression,
inline = TRUE))
)
)), actionButton("submit_depression", "Submit!"),
htmlOutput("depression")
)
) )
make other questionnaires
Using lapply() is a good approach to generate repetitive code blocks with slightly different input parameters. It allows you to avoid duplicating code and reduces the chances of introducing errors.
By using lapply(), you can loop over a sequence of integers (in this case, 1 to 9) and create a list of elements that share the same structure, but with different inputs. This makes it much easier to generate a questionnaire with many questions and options, as you only need to specify the question and answer choices once, and then the code takes care of generating the rest.
Additionally, using functions like lapply() can also make your code more modular and easier to maintain, as you can separate the logic for generating the input elements from the overall structure of the Shiny app. This can be especially useful when you need to make changes or add new features to your app.
= fluidPage(
ui tabsetPanel(
tabPanel("Questionnaire",
fluidRow(
br(),
column(12, "PHQ-9",
fluidRow(
column(5, "Questionnaire"),
column(7, "Scores")
))), fluidRow(
column(12, "",
fluidRow(
lapply(1:9, function(i){
list(
column(5, q_depression[[i]]),
column(7, radioButtons(sprintf("phq%s", i), "",
choiceNames = bt_depression,
choiceValues = sc_depression,
inline = TRUE)))
}))
)), actionButton("submit_depression", "Submit!"),
htmlOutput("depression", style = "font-size: 20px"),
htmlOutput("guide_depression", style = "font-size: 20px")
)
) )
= function(input, output, session){
server
observeEvent(input$submit_depression, {
<- reactive({
depression_score do.call(sum, lapply(1:9, function(i){
= paste0("phq", i)
ph return(as.numeric(input[[ph]]))
}))
})$depression <- renderText({
outputpaste("Your Score is", depression_score(), "point")
})
$guide_depression <- renderText({
outputguide_depression(depression_score())
})
}) }
= c("shiny", "tidyverse")
pkgs
for (pkg in pkgs){
if(!require(pkg, character.only = T)){
install.packages(pkg)
library(pkg, character.only = T)
}
}
<-list("1) Little interest or pleasure in doing things?",
q_depression "2) Feeling down, depressed, or hopeless?",
"3) Trouble falling or staying asleep, or sleeping too much?",
"4) Feeling tired or having little energy?",
"5) Poor appetite or overeating?",
"6) Feeling bad about yourself or that you are a failure or have let yourself or your family down?",
"7) Trouble concentrating on things, such as reading the newspaper or watching television?",
"8) Moving or speaking so slowly that other people could have noticed. Or the opposite being so figety or restless that you have been moving around a lot more than usual",
"9) Thoughts that you would be better off dead, or of hurting yourself")
<- c('Not at all',
bt_depression 'Several days',
'More than half the days',
'Nearly every day')
<- c(0,1,2,3)
sc_depression
<- data.frame(
interpre_depression "step" = c(1, 2, 3, 4, 5),
"severity" = c("Minimal depression",
"Mild depression",
"Moderate depression",
"Moderately severe depression",
"Severe depression"
), "guideline"= c("they are not severe enough to interfere with your daily life",
"You may have some moderate symptoms of depression,
and they may be interfering with your daily life to some extent.",
"You may have some severe symptoms of depression,
and they are interfering with your daily life to a significant extent.",
"You may have some very severe symptoms of depression,
and they are interfering with your daily life to a great extent.",
"You may have some extremely severe symptoms of depression,
and they are interfering with your daily life to a very great extent.")
%>%
) mutate(guideline2 = sprintf("%s!: %s", severity, guideline))
= function(i){
guide_depression if (i < 5) {
%>% filter(step ==1) %>% pull(guideline2) %>% as.character()
interpre_depression else if (i <10) {
} %>% filter(step ==2) %>% pull(guideline2) %>% as.character()
interpre_depression else if (i <15) {
} %>% filter(step ==3) %>% pull(guideline2) %>% as.character()
interpre_depression else if (i <20) {
} %>% filter(step ==4) %>% pull(guideline2) %>% as.character()
interpre_depression else {
} %>% filter(step ==5) %>% pull(guideline2) %>% as.character()
interpre_depression
} }