exploDOLQ / app.R
pbriss7's picture
Update app.R
b8b5684 verified
# Fonction pour filtrer les données
filter_data <- function(data, input, return_columns = NULL) {
# Vérifier si aucune colonne n'est sélectionnée
if (length(input$column) == 0) {
return(data[0])
}
# Filtrage par plage de dates
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 {
# Compute relative distribution
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)
# Ensure names.arg matches the length of relative_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)"),
# Add clickable images for each volume
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'))
)
),
# Second tab: Documentation
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) {
# Ensure the data is numeric
data_numeric <- as.numeric(reactive_data1()[, Annee_unique])
# Remove NA values
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
raw_counts <- hist(data_numeric, plot=FALSE, breaks=breaks_hist)$counts
# Relative 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)))
# Return data based on user's selection
if (input$dist_type == "raw") {
return(data.frame(Breaks = breaks, Counts = raw_counts))
} else {
return(data.frame(Breaks = breaks, RelativeCounts = relative_counts))
}
}
}
# Ensure a dataframe is always returned
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({
# Check if 'Annee_unique' column exists and has data
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 {
# Compute relative distribution
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)
# Ensure names.arg matches the length of relative_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)
# Check if 'Annee_unique' column exists and has data
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 {
# Compute relative distribution
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)
# Ensure names.arg matches the length of relative_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({
# Read the content of the README.md file
readme_content <- readLines("README.md", warn = FALSE)
# Convert the markdown content to HTML for rendering in the Shiny app
HTML(markdown::markdownToHTML(text = readme_content, fragment.only = TRUE))
})
}
shinyApp(ui = ui, server = server)