|
|
|
filter_data <- function(data, input, return_columns = NULL) { |
|
|
|
if (length(input$column) == 0) { |
|
return(data[0]) |
|
} |
|
|
|
|
|
filtered_data <- data[ |
|
Annee_unique >= input$date_range[1] & |
|
Annee_unique <= input$date_range[2] |
|
] |
|
|
|
pattern <- input$motcle |
|
matches <- rep(FALSE, nrow(filtered_data)) |
|
|
|
for (col in input$column) { |
|
if (input$regex) { |
|
matches <- matches | grepl(pattern, filtered_data[[col]], ignore.case = TRUE) |
|
} else { |
|
matches <- matches | grepl(pattern, filtered_data[[col]], fixed = TRUE, ignore.case = TRUE) |
|
} |
|
} |
|
|
|
filtered_data <- filtered_data[matches, ] |
|
|
|
if (!is.null(return_columns)) { |
|
filtered_data <- filtered_data[, ..return_columns] |
|
} |
|
|
|
return(filtered_data) |
|
} |
|
|
|
plot_histogram <- function(data_frame) { |
|
if ("Annee_unique" %in% names(data_frame) && nrow(data_frame) > 0) { |
|
min_year <- min(na.omit(data_frame[, Annee_unique])) |
|
max_year <- max(na.omit(data_frame[, Annee_unique])) |
|
breaks_hist <- seq(min_year, max_year, length.out = input$num_breaks + 1) |
|
|
|
if (input$dist_type == "raw") { |
|
hist(data_frame()[, Annee_unique], |
|
main = "Distribution brute des notices", |
|
xlab = "Année", |
|
ylab = "Nombre", |
|
border = "blue", |
|
col = "lightblue", |
|
breaks = breaks_hist) |
|
} else { |
|
|
|
filtered_counts <- hist(data_frame[, Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
total_counts <- hist(data[data$Annee_unique %in% data_frame[, Annee_unique], Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
relative_counts <- ifelse(total_counts == 0, 0, filtered_counts / total_counts) |
|
|
|
|
|
names_for_bars <- round(seq(min_year, max_year, length.out = length(relative_counts))) |
|
|
|
barplot(relative_counts, |
|
main = "Distribution relative des notices", |
|
xlab = "Année", |
|
ylab = "Fréquence relative", |
|
border = "blue", |
|
col = "lightblue", |
|
space = 0, |
|
names.arg = names_for_bars) |
|
} |
|
} else { |
|
plot.new() |
|
title(main = "No data available for the selected criteria") |
|
} |
|
} |
|
|
|
inst_ext_f <- function(extension) { |
|
if(!extension %in% rownames(installed.packages())) { |
|
install.packages(extension, dependencies = TRUE) |
|
} |
|
require(extension, character.only = TRUE) |
|
} |
|
|
|
|
|
extensions <- c("shiny", |
|
"data.table", |
|
"DT", |
|
"shinyWidgets", |
|
"stringr", |
|
"markdown") |
|
|
|
sapply(extensions, inst_ext_f) |
|
|
|
data <- readRDS("dolq_min.RDS") |> setDT() |
|
|
|
readme_content <- readLines("README.md", warn = FALSE) |
|
|
|
ui <- fluidPage( |
|
titlePanel("Dictionnaire des oeuvres littéraires du Québec, t. 1-6"), |
|
tabsetPanel( |
|
tabPanel("Recherche plein texte", |
|
sidebarLayout( |
|
sidebarPanel( |
|
noUiSliderInput(inputId = "date_range", |
|
label = "Sélectionner une période:", |
|
min = 1830, |
|
max = 1980, |
|
value = c(1830, 1980), |
|
format = wNumbFormat(decimals = 0), |
|
tooltips = TRUE), |
|
br(), |
|
|
|
pickerInput( |
|
inputId = "column", |
|
label = h5("Choisissez les colonnes où effectuer la recherche:"), |
|
choices = c("Auteur_oeuvre", "Titre", "Auteur_notice", "Article", |
|
"Depouillement", "Details_bibliographiques"), |
|
selected = "Article", |
|
options = list(`actions-box` = TRUE), |
|
multiple = TRUE |
|
), |
|
pickerInput( |
|
inputId = "additional_columns", |
|
label = h5("Choisissez les colonnes à afficher:"), |
|
choices = c("Id", "Auteur_oeuvre", "Titre", "Annee_parution", "Auteur_notice", "Article", "Volume", "Depouillement", "Details_bibliographiques"), |
|
selected = c("Auteur_oeuvre", "Titre", "Article"), |
|
options = list(`actions-box` = TRUE), |
|
multiple = TRUE |
|
), |
|
textInput( |
|
inputId = "motcle", |
|
label = h5("Chaine de caractères à rechercher"), |
|
value = "Montréal" |
|
), |
|
prettySwitch( |
|
inputId = "regex", |
|
label = "Utiliser une expression régulière?", |
|
fill = FALSE, |
|
status = "primary" |
|
), |
|
downloadButton("downloadData", "Exporter le résultat de la table (csv)"), |
|
width = 4, |
|
hr(), |
|
|
|
tags$head(tags$link(rel = "stylesheet", href = "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css")), |
|
|
|
|
|
h5("Antisèche - expressions régulières"), |
|
tags$a(href = "regex.pdf", target = "_blank", |
|
tags$img(src = "regex.jpg", alt = "Thumbnail", width = "100%")), |
|
|
|
hr(), |
|
h5("Accéder aux volumes (pdf)"), |
|
|
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-1-des-origines-a-1900/", target = "_blank", |
|
tags$img(src = "DOLQ_01.jpg", alt = "Volume 1", width = "50%")), |
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-2-1900-a-1939/", target = "_blank", |
|
tags$img(src = "DOLQ_02.jpg", alt = "Volume 2", width = "50%")), |
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-3-1940-a-1959/", target = "_blank", |
|
tags$img(src = "DOLQ_03.jpg", alt = "Volume 3", width = "50%")), |
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-4-1960-1969/", target = "_blank", |
|
tags$img(src = "DOLQ_04.jpg", alt = "Volume 4", width = "50%")), |
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-5-1970-1975/", target = "_blank", |
|
tags$img(src = "DOLQ_05.jpg", alt = "Volume 5", width = "50%")), |
|
tags$a(href = "https://crilcq.org/dictionnaire-des-oeuvres-litteraires-du-quebec-tome-5-1970-1975/", target = "_blank", |
|
tags$img(src = "DOLQ_06.jpg", alt = "Volume 6", width = "50%")), |
|
), |
|
|
|
mainPanel(h3("Distribution chronologique des notices"), |
|
|
|
radioButtons(inputId = "dist_type", |
|
label = "Type de distribution:", |
|
choices = list("Distribution brute" = "raw", |
|
"Distribution relative" = "relative"), |
|
selected = "raw"), |
|
|
|
numericInput("num_breaks", label = "Nombre d'intervalles:", value = 65, min = 1), |
|
|
|
plotOutput("histogram"), |
|
|
|
downloadButton("download_graph", "Exporter le graphique"), |
|
downloadButton("download_table", "Exporter les données du graphique"), |
|
|
|
h3("Table"), |
|
textOutput("filtered_count"), |
|
DT::dataTableOutput('table')) |
|
) |
|
), |
|
|
|
|
|
|
|
tabPanel("Documentation", |
|
uiOutput("readme") |
|
) |
|
) |
|
) |
|
|
|
server <- function(input, output) { |
|
|
|
reactive_data <- reactive({ |
|
filter_data(data, input, input$additional_columns) |
|
}) |
|
|
|
reactive_data1 <- reactive({ |
|
filter_data(data, input) |
|
}) |
|
|
|
filtered_count <- reactive({ |
|
nrow(reactive_data()) |
|
}) |
|
|
|
hist_data <- reactive({ |
|
if ("Annee_unique" %in% names(reactive_data1()) && nrow(reactive_data1()) > 0) { |
|
|
|
data_numeric <- as.numeric(reactive_data1()[, Annee_unique]) |
|
|
|
|
|
data_numeric <- na.omit(data_numeric) |
|
|
|
if (length(data_numeric) > 0) { |
|
min_year <- min(data_numeric) |
|
max_year <- max(data_numeric) |
|
breaks_hist <- seq(min_year, max_year, length.out = input$num_breaks + 1) |
|
|
|
|
|
raw_counts <- hist(data_numeric, plot=FALSE, breaks=breaks_hist)$counts |
|
|
|
|
|
total_counts <- hist(data[data$Annee_unique %in% reactive_data1()[, Annee_unique], Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
|
|
relative_counts <- ifelse(total_counts == 0, 0, raw_counts / total_counts) |
|
|
|
breaks <- round(seq(min_year, max_year, length.out = length(raw_counts))) |
|
|
|
|
|
if (input$dist_type == "raw") { |
|
return(data.frame(Breaks = breaks, Counts = raw_counts)) |
|
} else { |
|
return(data.frame(Breaks = breaks, RelativeCounts = relative_counts)) |
|
} |
|
} |
|
} |
|
|
|
return(data.frame(Breaks = numeric(0), Counts = numeric(0))) |
|
}) |
|
|
|
|
|
output$filtered_count <- renderText({ |
|
paste("Nombre de notices filtrées:", filtered_count()) |
|
}) |
|
|
|
output$table <- DT::renderDataTable({ |
|
datatable(reactive_data(), options = list(searching = FALSE), |
|
callback = JS(paste0(" |
|
table.on('draw.dt', function() { |
|
var keyword = '", input$motcle, "'; |
|
$('td').each(function() { |
|
var content = $(this).html(); |
|
var highlighted = content.replace(new RegExp(keyword, 'gi'), function(match) { |
|
return '<span style=\"background-color: yellow;\">' + match + '</span>'; |
|
}); |
|
$(this).html(highlighted); |
|
}); |
|
}); |
|
"))) |
|
}) |
|
|
|
output$downloadData <- downloadHandler( |
|
filename = function() { |
|
paste("filtered_data-", Sys.Date(), ".csv", sep="") |
|
}, |
|
content = function(file) { |
|
fwrite(reactive_data(), file) |
|
} |
|
) |
|
|
|
output$histogram <- renderPlot({ |
|
|
|
if ("Annee_unique" %in% names(reactive_data1()) && nrow(reactive_data1()) > 0) { |
|
min_year <- min(na.omit(reactive_data1()[, Annee_unique])) |
|
max_year <- max(na.omit(reactive_data1()[, Annee_unique])) |
|
breaks_hist <- seq(min_year, max_year, length.out = input$num_breaks + 1) |
|
|
|
if (input$dist_type == "raw") { |
|
hist(reactive_data1()[, Annee_unique], |
|
main = "Distribution brute des notices", |
|
xlab = "Année", |
|
ylab = "Nombre", |
|
border = "blue", |
|
col = "lightblue", |
|
breaks = breaks_hist) |
|
} else { |
|
|
|
filtered_counts <- hist(reactive_data1()[, Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
total_counts <- hist(data[data$Annee_unique %in% reactive_data1()[, Annee_unique], Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
relative_counts <- ifelse(total_counts == 0, 0, filtered_counts / total_counts) |
|
|
|
|
|
names_for_bars <- round(seq(min_year, max_year, length.out = length(relative_counts))) |
|
|
|
barplot(relative_counts, |
|
main = "Distribution relative des notices", |
|
xlab = "Année", |
|
ylab = "Fréquence relative", |
|
border = "blue", |
|
col = "lightblue", |
|
space = 0, |
|
names.arg = names_for_bars) |
|
} |
|
} else { |
|
plot.new() |
|
title(main = "No data available for the selected criteria") |
|
} |
|
}) |
|
|
|
output$download_graph <- downloadHandler( |
|
filename = function() { |
|
paste("histogram_graph", Sys.Date(), ".png", sep = "_") |
|
}, |
|
content = function(file) { |
|
png(file) |
|
|
|
if ("Annee_unique" %in% names(reactive_data1()) && nrow(reactive_data1()) > 0) { |
|
min_year <- min(na.omit(reactive_data1()[, Annee_unique])) |
|
max_year <- max(na.omit(reactive_data1()[, Annee_unique])) |
|
breaks_hist <- seq(min_year, max_year, length.out = input$num_breaks + 1) |
|
|
|
if (input$dist_type == "raw") { |
|
hist(reactive_data1()[, Annee_unique], |
|
main = "Distribution brute des notices", |
|
xlab = "Année", |
|
ylab = "Nombre", |
|
border = "blue", |
|
col = "lightblue", |
|
breaks = breaks_hist) |
|
} else { |
|
|
|
filtered_counts <- hist(reactive_data1()[, Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
total_counts <- hist(data[data$Annee_unique %in% reactive_data1()[, Annee_unique], Annee_unique], plot=FALSE, breaks=breaks_hist)$counts |
|
relative_counts <- ifelse(total_counts == 0, 0, filtered_counts / total_counts) |
|
|
|
|
|
names_for_bars <- round(seq(min_year, max_year, length.out = length(relative_counts))) |
|
|
|
barplot(relative_counts, |
|
main = "Distribution relative des notices", |
|
xlab = "Année", |
|
ylab = "Fréquence relative", |
|
border = "blue", |
|
col = "lightblue", |
|
space = 0, |
|
names.arg = names_for_bars) |
|
} |
|
} else { |
|
plot.new() |
|
title(main = "No data available for the selected criteria") |
|
} |
|
dev.off() |
|
} |
|
) |
|
|
|
output$download_table <- downloadHandler( |
|
filename = function() { |
|
paste("histogram_data", Sys.Date(), ".csv", sep = "_") |
|
}, |
|
content = function(file) { |
|
write.csv(hist_data(), file, row.names = FALSE) |
|
} |
|
) |
|
output$readme <- renderUI({ |
|
|
|
readme_content <- readLines("README.md", warn = FALSE) |
|
|
|
|
|
HTML(markdown::markdownToHTML(text = readme_content, fragment.only = TRUE)) |
|
}) |
|
|
|
} |
|
|
|
|
|
shinyApp(ui = ui, server = server) |