Skip to content

Commit

Permalink
UI fixes, server code reorganization, CSV download fix #1
Browse files Browse the repository at this point in the history
  • Loading branch information
jzpero committed Apr 12, 2020
1 parent 4c6979c commit 26bf606
Show file tree
Hide file tree
Showing 8 changed files with 1,235 additions and 79 deletions.
File renamed without changes.
1,110 changes: 1,110 additions & 0 deletions data/current_2020-04-12-20-51-11.csv

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions data/statistics.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
date,search,included,screened
"April 7, 2020",1890,385,1217
"April 11, 2020",3288,531,2289
9 changes: 7 additions & 2 deletions markdown/About-Proj.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
## What is this?
Recent literature on COVID-19 is highly variable in scope, quality, and applicability to the front-line physician. In a time where information and time are valuable resources, there must be a resource that provides curated primary and secondary literature so that clinical decisions can be made with more confidence. This project provides a way to browse current and relevant literature on COVID-19 that has been curated via a systematic review approach.
Recent literature on COVID-19 is highly variable in scope, quality, and applicability to the front-line physician. In a time where information and time are valuable resources, there must be a resource that provides curated primary and secondary literature so that clinical decisions can be made with more confidence.

This project aims to provide a way to explore higher-quality current literature on COVID-19 that has been curated via a systematic review approach.

## Contributors
Citations and data were reviewed and curated by **Becky Jones**, **Daniel Levin**, **Hannah Kearney**, **Jasper Ho**, **Jillian Howden**, **John Kim**, **Maya Amar**, **Meghan Glibbery**, and **Sara Markovic**, all medical students at McMaster University.<br>This tool was coded and designed by **Jasper Ho** (<a href="https://www.twitter.com/jzpero">@jzpero</a>) in R using Shiny.
Citations are reviewed by **Becky Jones**, **Daniel Levin**, **Hannah Kearney**, **Jasper Ho**, **Jillian Howden**, **John Kim**, **Maya Amar**, **Meghan Glibbery**, and **Sara Markovic**, all medical students at McMaster University.

This tool is created, maintained, and updated by **Jasper Ho** ([Twitter](https://www.twitter.com/jzpero), [GitHub](https://www.github.com/jzpero)).

The project was conceptualized and is supervised by **Dr. Mark Crowther** MD, MSc, FRCPC.

## Contact Us
Expand Down
18 changes: 9 additions & 9 deletions markdown/Methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ We searched for relevant articles on PubMed with the following search strategy:

Our search is ongoing as new literature emerges. Our repository of unfiltered articles has been updated on the following dates:

- March 28, 2020
- April 8, 2020
- March 28, 2020 (N=1890)
- April 8, 2020 (N=3288)

## Inclusion Criteria
No strict inclusion criteria were established; the purpose of this literature review is to provide high-yield pertinent research to the front-line clinician across a breadth of areas, specifically oriented towards the Ontario/Canada/North American context of COVID-19.
Expand Down Expand Up @@ -42,15 +42,15 @@ Few strict exclusion criteria were applied. As above, our assessment of referenc
- Explanation of journal responses to COVID-19
- Relevant only to overseas/international settings

## Screening Methods
References were independently screened via title/abstract review by two or more reviewers each.
Disagreements were resolved by group consensus or a third reviewer when necessary.

## Categorization
Reference type, specialties of interest, and relevance to front-line clinicians were assessed and assigned.
## Screening and Tagging Methods
We review new references in a temporally sequential order, oldest to newest.
References are independently screened via title/abstract review by two or more reviewers each.
Disagreements are resolved by group consensus or a third reviewer when necessary.
Reference type, specialties of interest, and relevance to front-line clinicians are assessed and assigned.
We update this website with newly included references on a regular basis.

## Webtool Implementation
This tool has been written in Shiny in R. Source code and data are available at https://github.com/jzpero/covid19lit. Interested in contributing? Contact: jasper.ho (at) medportal.ca.
This fully open-source tool has been written in Shiny in R. Source code, data, and acknowledgements are available at https://github.com/jzpero/covid19lit. The backend is an Amazon EC2 instance running Shiny Server. Interested in contributing? Contact: jasper.ho (at) medportal.ca.

## Notes
This tool is a work in progress. It was also developed by a non-professional. It relies on online data from PubMed parsed from official tools, with custom code or public libraries. As such, there may be occasional errors. Please do not rely on any specific data found on this online tool without appropriate confirmation from the source. Errors may include:
Expand Down
90 changes: 58 additions & 32 deletions server.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
library(dplyr)

server <- function(input, output, session) {
#Case formatting from https://stat.ethz.ch/R-manual/R-devel/library/base/html/chartr.html
capwords <- function(s, strict = FALSE) {
cap <- function(s) paste(toupper(substring(s, 1, 1)),
{s <- substring(s, 2); if(strict) tolower(s) else s},
sep = "", collapse = " " )
sapply(strsplit(s, split = " "), cap, USE.NAMES = !is.null(names(s)))
}

#Create a PubMed link in HTML
createLink <- function(PMID, text) {
sprintf('<a href="https://www.ncbi.nlm.nih.gov/pubmed/%s" target="_blank">%s</a>', PMID, text)
}

included.headers <- c("TitleLinks", "Author", "Journal","Date", "PMID", "Type of Study", "Specialties")

server <- function(input, output, session) { # Executes once per session (no need to restart service)
#Update the data once
link <- list.files("data/", pattern="(current)", full.names=TRUE)[1]

#Case formatting from https://stat.ethz.ch/R-manual/R-devel/library/base/html/chartr.html
capwords <- function(s, strict = FALSE) {
cap <- function(s) paste(toupper(substring(s, 1, 1)),
{s <- substring(s, 2); if(strict) tolower(s) else s},
sep = "", collapse = " " )
sapply(strsplit(s, split = " "), cap, USE.NAMES = !is.null(names(s)))
}

#Data Processing (done once)
rawtable <- read.csv(link, sep = ",", na.strings="", encoding = "UTF-8", check.names=FALSE, stringsAsFactors=FALSE)
date_data <- read.csv("data/date_output.csv", header=T, colClasses = c("character", "character"))
Expand All @@ -29,36 +36,31 @@ server <- function(input, output, session) {
}
filtered.table$Date <- anytime::anydate(filtered.table$Date)

#Create dropdown choices
#Create filter choices
unique.authors <- lapply(strsplit(paste(filtered.table$Author, collapse=','), ","), trimws)[[1]]
unique.authors <<- sort(unique(unique.authors[lapply(unique.authors, nchar) > 0]))
unique.journals <- sort(unique(filtered.table$Journal))
unique.studytypes <<- sort(unique(filtered.table$'Type of Study'))
unique.specialties <<- sort(c("Internal Medicine", "General", "Dermatology", "ICU", "Emergency Medicine", "Anesthesia", "Radiology", "OBGYN", "Public Health", "Cardiology", "Oncology", "Psych", "Family Medicine", "Gastroenterology", "Geriatrics", "Hematology", "Infectious Disease", "Immunology", "Medical Education", "Microbiology", "Nephrology", "Neurology", "Ophthalmology", "Palliative Care", "Pathology", "Pediatrics","Respirology", "Rheumatology", "Surgery", "Urology"))

# Special processing of specialty data
spec.out <- vector("list", length=N)
spec.cols <- grep("Spec", headers)
# View(colnames(filtered.table)[spec.cols])
for (i in 1:N) {
k <- unlist(filtered.table[i,spec.cols], use.names = F)
k <- sort(k[!is.na(k)])
spec.out[[i]] <- k
}
filtered.table$Areas <- spec.out
filtered.table$Specialties <- sapply(filtered.table$Areas, function(x) paste(unlist(x), collapse=", "))

#Create a PubMed link in HTML
createLink <- function(PMID, text) {
sprintf('<a href="https://www.ncbi.nlm.nih.gov/pubmed/%s" target="_blank">%s</a>', PMID, text)
}

#Populate the search filters
updateSelectInput(session, "journal", choices = c("Select a journal" = "", unique.journals))
updateSelectInput(session, "author", choices = c("Select authors" = "", unique.authors))
updateSelectInput(session, "study", choices = c("Select a type" = "", unique.studytypes))
updateSelectInput(session, "specialty", choices = c("Select an area of interest" = "", unique.specialties))

#Initiate table
#Initiate display table
display.table <- filtered.table

#clear all button actions
Expand Down Expand Up @@ -104,7 +106,7 @@ server <- function(input, output, session) {
if (!is.null(input$specialty) & nrow(display.table)) {
#Initialize FALSE Vector
v <- vector("logical",nrow(display.table))
if (input$specSwitch){
if (input$specSwitch == "Any term"){
#iterate over author rows and flag as TRUE if ANY of the selected authors present
for (i in 1:nrow(display.table)) {
for (query in input$specialty) {
Expand All @@ -124,30 +126,54 @@ server <- function(input, output, session) {
if (!is.null(input$ex1_rows_selected)) {
HTML(paste0(
trimws(display.table[input$ex1_rows_selected,"Author"]), ". ",
"<b>",display.table[input$ex1_rows_selected,"Title"], "</b> ",
"<b>",display.table[input$ex1_rows_selected,"TitleLinks"], "</b> ",
"<i>", trimws(display.table[input$ex1_rows_selected,"Journal"]), "</i>. <br><br>", if (is.na(display.table[input$ex1_rows_selected, "Abstract"])) "No abstract." else display.table[input$ex1_rows_selected, "Abstract"]
))} else HTML("<i>Select a reference...</i>")
)

output$N <- renderText(nrow(display.table))

#Create Links
display.table$Title <- createLink(display.table$PMID, display.table$Title)
display.table$TitleLinks <- createLink(display.table$PMID, display.table$Title)

#Export option
output$export <- downloadHandler(
filename = function() {
paste("references",Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(display.table[,gsub("TitleLinks", "Title", included.headers)], file, row.names = FALSE)
}
)

# PDF Rmd Report
# output$report <- downloadHandler(
# filename = "report.pdf",
# content = function(file) {
# # Copy the report file to a temporary directory before processing it, in
# # case we don't have write permissions to the current working dir (which
# # can happen when deployed).
# tempReport <- file.path(tempdir(), "report.Rmd")
# file.copy("markdown/report.Rmd", tempReport, overwrite = TRUE)
#
# # Set up parameters to pass to Rmd document
# params <- list(dtable=display.table[,included.headers])
#
# # Knit the document, passing in the `params` list, and eval it in a
# # child of the global environment (this isolates the code in the document
# # from the code in this app).
# rmarkdown::render(tempReport, output_file = file,
# params = params,
# envir = new.env(parent = globalenv())
# )
# }
# )

#Output
included.headers <- c("Title", "Author", "Journal","Date", "PMID", "Type of Study", "Specialties")
DT::datatable(
display.table[,included.headers],
extensions = "Responsive",
options = list(pageLength = 10, order = list(list(3, "desc"), list(4, "desc"))),
rownames= FALSE, escape=FALSE, selection = 'single')

# #Export option
# output$export <- downloadHandler(
# filename = function() {
# paste("references",Sys.Date(),".csv", sep = "")
# },
# content = function(file) {
# write.csv(display.table[,included.headers], file, row.names = FALSE)
# }
# )
})
}
}
82 changes: 47 additions & 35 deletions ui.R
Original file line number Diff line number Diff line change
@@ -1,54 +1,66 @@
filterPanel <- wellPanel(
id = "searchpanel",
p(strong("Filter Options"), br(), "Any combination of filters accepted."),
selectInput(inputId = "journal", label="Journal", choices = NULL, multiple = TRUE, ),
div(style = "margin-top:-15px"),
selectInput(inputId = "study", "Type of Study", choices = NULL, multiple = TRUE),
div(style = "margin-top:-15px"),
selectInput(inputId = "author", "Author(s)",choices = NULL, multiple = TRUE),
div(style = "margin-top:-15px"),
selectInput(inputId = "specialty", "Specialty Bucket",choices = NULL, multiple = TRUE),
div(style = "margin-top:-15px"),
shinyWidgets::radioGroupButtons(inputId="specSwitch", size="sm", label="Specialty matches:", choices=c("Any term", "All terms"), selected="Any term", status="info"),
div(style = "margin-top:-10px"),
hr(),
div(style = "margin-top:-15px"),
p(textOutput("N", inline = TRUE), " result(s)."),
fluidRow(
column(6,dropdown(
downloadButton(outputId = "export", label = "CSV", class="btn-secondary btn-sm"),
# downloadButton(outputId = "report", label = "PDF", class="btn-secondary btn-sm"),
status="btn-primary btn-sm",
size="sm",
label="Download results"
)),
column(6, actionButton(inputId = "clearAll", "Clear filters", class="btn-primary btn-sm"))
)
)

ui <- navbarPage(
title = 'COVID-19 Literature Review',
position = c("fixed-top"),
tabPanel(
'All',
'Included',
id="tab-panel",
shinyjs::useShinyjs(),
fluidRow(
column(3,
fluidRow(
wellPanel(
id = "searchpanel",
p(strong("Filter Options")),
selectInput(inputId = "journal", label="Journal", choices = NULL, multiple = TRUE, ),
selectInput(inputId = "study", "Type of Study", choices = NULL, multiple = TRUE),
selectInput(inputId = "author", "Author(s)",choices = NULL, multiple = TRUE),
selectInput(inputId = "specialty", "Specialty Bucket",choices = NULL, multiple = TRUE),
shinyWidgets::switchInput(inputId="specSwitch", size="mini", label="Match", onLabel = "Any", offLabel = "All", value=TRUE, offStatus = "success"),
hr(),
actionButton(inputId = "clearAll", "Clear all", class="btn-primary btn-sm")
# downloadButton(outputId = "export", label = "Download all", class="btn-secondary btn-sm")
# downloadButton(outputId = "exportselected", label = "Download selected", class="btn-secondary btn-sm")
)
),
fluidRow(
wellPanel(
htmlOutput("ref_caption")
)
)
),
column(9,
DT::dataTableOutput('ex1')
)
column(3, filterPanel, wellPanel(htmlOutput("ref_caption"))),
column(9, DT::dataTableOutput('ex1'))
)
),
# tabPanel("Critical Care"),
# tabPanel("Internal Medicine"),
# tabPanel("Emergency Medicine"),
# tabPanel("Pediatrics"),
# tabPanel("Radiology"),
# tabPanel("Epi and Public Health"),
# tabPanel("Basic Sciences"),
# tabPanel("Unreviewed",
# fluidRow(
# column(3,
# fluidRow(
# filterPanel
# ),
# fluidRow(
# wellPanel(
# htmlOutput("ref_caption")
# )
# )
# ),
# column(9)
# )
# ),
navbarMenu("About",
tabPanel("The Project",
tags$style(type="text/css","body {padding-top: 70px;}"),
tags$style(type="text/css","body {padding-top:60px;}"),
fluidRow(column(3),
column(6,wellPanel(HTML(includeMarkdown("markdown/About-Proj.md")))),
column(3))
),
tabPanel('Methods',
tags$style(type="text/css","body {padding-top: 70px;}"),
fluidRow(column(3),
column(6,wellPanel(HTML(includeMarkdown("markdown/Methods.md")))),
column(3))
Expand Down
2 changes: 1 addition & 1 deletion www/yeti.css
Original file line number Diff line number Diff line change
Expand Up @@ -3936,7 +3936,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
}
}
.navbar-default {
background-color: #940049; /*originally 333333*/
background-color: #7a003c; /*originally 333333*/
border-color: #222222;
}
.navbar-default .navbar-brand {
Expand Down

0 comments on commit 26bf606

Please sign in to comment.