diff --git a/index.Rmd b/index.Rmd index b199915ea..7fa2efe6f 100644 --- a/index.Rmd +++ b/index.Rmd @@ -21,6 +21,13 @@ library(plotly) library(reactable) library(glue) source("R/global_translations.R") + +# Set colors to translation status +colors <- c( + "Translated" = "#5495CFFF", + "Untranslated" = "#DB4743FF", + "Fuzzy" = "#F5AF4DFF" +) ``` Sidebar {.sidebar data-width=200} @@ -61,132 +68,265 @@ valueBox(total_untrans_msg, icon = "fa-comment-slash", color = "white") valueBox(total_fuzzy_msg, icon = "fa-puzzle-piece", color = "white") ``` -Row {data-height=70} +Row {data-height=750} ----------------------------------------------------------------------- +### Translatation progress | Per Package -```{r data} -trans_stats <- SharedData$new(final_df) -``` +```{r} -```{r filters} +# Calculate count and percentage for all languages +final_df_all <- final_df |> + group_by(package) |> + summarise(across(c(translated_count,untranslated_count, + fuzzy_count), sum)) |> + mutate(language = "All", .after = package) |> + rowwise() |> + mutate( + pc_trans_count = translated_count / sum(c_across(translated_count:fuzzy_count)), + pc_untrans_count = untranslated_count / sum(c_across(translated_count:fuzzy_count)), + pc_fuzzy_count = fuzzy_count / sum(c_across(translated_count:fuzzy_count)) + ) -# Filter Select Input - Language -filter_select(id = "language", - label = "Select Translation Language", - sharedData = trans_stats, - group = ~language) +# Join languages with all +final_df_neg <- bind_rows(final_df_all, final_df) |> + mutate(pc_untrans_count = -pc_untrans_count, + pc_fuzzy_count = -pc_fuzzy_count, + pc_trans_count = pc_trans_count) |> + pivot_longer(cols = starts_with("pc"), values_to = "percentage", names_to = "trans_status") |> + mutate(trans_status = factor(trans_status, + levels = c("pc_trans_count", "pc_untrans_count", "pc_fuzzy_count"), + labels = c("Translated", "Untranslated", "Fuzzy"))) + + +# Get unique languages +languages <- unique(final_df_neg$language) +n_lang <- length(languages) + +# Create buttons for each language +buttons <- lapply(seq_len(n_lang), function(i) { + # Each language has a trace for each status + n_status <- 3 # Translated, Untranslated, Fuzzy + visible <- logical(n_lang * n_status) + # Turn on visibility for language i with this button + visible[((i - 1) * n_status + 1):(i * n_status)] <- TRUE + list( + method = "restyle", + args = list("visible", visible), + label = languages[i] + ) +}) + +# Create the plot with all languages visible +fig <- plot_ly(height = 700) + +# Add traces for each language +for(lang in languages) { + fig <- fig |> + add_bars(data = final_df_neg[final_df_neg$language == lang, ], + x = ~ percentage, + y = ~ package, + color = ~ trans_status, + colors = colors, + visible = if (lang == "All") TRUE else FALSE) +} + +fig <- fig |> + layout( + xaxis = list(title = 'Progress', tickformat = ',.0%'), + yaxis = list(title = ''), + barmode = 'relative', + legend = list(x = 1, + y = 0), + updatemenus = list( + list( + type = "dropdown", + buttons = buttons, + x = 1.25, + y = 1 + ) + ) + ) +fig ``` -Row {data-height=450} ------------------------------------------------------------------------ -### Graph of Translated vs Untranslated Messages | Per Language +### Translatation progress | Per Language ```{r} -trans_stats <- plot_ly(trans_stats, x = ~package, y = ~translated_count, type = 'bar', name = 'Translated Messages') -trans_stats <- trans_stats %>% add_trace(y = ~untranslated_count, name = 'Untranslated Messages') -trans_stats <- trans_stats %>% add_trace(y = ~fuzzy_count, name = 'Fuzzy Messages') -trans_stats <- trans_stats %>% layout(yaxis = list(title = 'Message Count'), xaxis = list(title = "Packages"), barmode = 'group') -trans_stats -``` - -Row {data-height=450} ------------------------------------------------------------------------ -### Count of Translated Messages | Across Packages +# Data manipulation +lang_df <- final_df |> + group_by(language) |> + summarise( + translated_count = sum(translated_count, na.rm = TRUE), + untranslated_count = sum(untranslated_count, na.rm = TRUE), + fuzzy_count = sum(fuzzy_count, na.rm = TRUE), + Total = translated_count + untranslated_count + fuzzy_count + ) |> + mutate( + Translated = case_when( + translated_count > 0 & round(translated_count/Total*100, 0) == 0 ~ 1, + TRUE ~ round(translated_count/Total*100, 0) + ), + Fuzzy = case_when( + fuzzy_count > 0 & round(fuzzy_count/Total*100, 0) == 0 ~ 1, + TRUE ~ round(fuzzy_count/Total*100, 0) + ), + Untranslated = 100 - Translated - Fuzzy + ) -```{r} -complete_trans_df %>% - reactable( - ., - pagination = TRUE, - showPageSizeOptions = TRUE, - highlight = TRUE, - defaultSorted = "translated_count", - defaultColDef = colDef(headerClass = "header", align = "left"), - columns = list( - package = colDef( - name = "Package Name", - width = 150, - defaultSortOrder = "desc", - filterable = TRUE, - ), - language = colDef( - name = "Language", - width = 150, - filterable = TRUE, - ), - untranslated_count = colDef( - show = FALSE +# Generate layout for 1 waffle chart +create_waffle_coordinates <- function(total_squares, width = 10) { + x <- numeric(total_squares) + y <- numeric(total_squares) + + for (i in 0:(total_squares - 1)) { + x[i + 1] <- i %% width + y[i + 1] <- floor(i / width) + } + return(data.frame(x = x, y = y)) +} + + +build_waffle <- function(data) { + + all_shapes <- list() + all_annotations <- list() + + # -- Layout configuration -- + cols <- 6 + rows <- ceiling(nrow(data) / cols) + + # Gap between charts + x_gap <- 11 + y_gap <- 12.5 + + # --- Loop 1: Grid shapes (Percentages) --- + for (i in 1:nrow(data)) { + language <- data$language[i] + + # Use percentages to build the 10x10 grid + counts <- c( + Translated = data$Translated[i], + Untranslated = data$Untranslated[i], + Fuzzy = data$Fuzzy[i] + ) + + # Grid position calculation + col_idx <- (i - 1) %% cols + row_idx <- floor((i - 1) / cols) + + x_offset <- col_idx * x_gap + y_offset <- (rows - 1 - row_idx) * y_gap + + # Create coordinates + grid <- create_waffle_coordinates(sum(counts)) + # browser() + grid$category <- factor(rep(names(counts), times = counts), levels = c("Translated", "Untranslated", "Fuzzy")) + + + # Add title annotation + all_annotations[[length(all_annotations) + 1]] <- list( + x = x_offset + 5, + y = y_offset + 10.75, + text = language, + showarrow = FALSE, + font = list(size = 12) + ) + + # Create shapes + for (j in 1:nrow(grid)) { + cat_name <- grid$category[j] + + shape <- list( + type = "rect", + x0 = grid$x[j] + x_offset, + y0 = grid$y[j] + y_offset, + x1 = grid$x[j] + x_offset + 0.9, + y1 = grid$y[j] + y_offset + 0.9, + fillcolor = colors[[cat_name]], + line = list(width = 0), + layer = "below" + ) + all_shapes[[length(all_shapes) + 1]] <- shape + } + } + + # --- Loop 2: Hover data (Counts) --- + hover_data <- data.frame() + + for (i in 1:nrow(data)) { + language <- data$language[i] + + pct_counts <- c( + Translated = data$Translated[i], + Untranslated = data$Untranslated[i], + Fuzzy = data$Fuzzy[i] + ) + + real_counts <- c( + Translated = data$translated_count[i], + Untranslated = data$untranslated_count[i], + Fuzzy = data$fuzzy_count[i] + ) + + col_idx <- (i - 1) %% cols + row_idx <- floor((i - 1) / cols) + x_offset <- col_idx * x_gap + y_offset <- (rows - 1 - row_idx) * y_gap + + grid <- create_waffle_coordinates(sum(pct_counts)) + grid$category <- factor(rep(names(pct_counts), times = pct_counts), levels = c("Translated", "Untranslated", "Fuzzy")) + + + grid$real_x <- grid$x + x_offset + 0.45 + grid$real_y <- grid$y + y_offset + 0.45 + grid$language <- language + + grid$Total <- rep(real_counts, times = pct_counts) + + hover_data <- rbind(hover_data, grid) + } + + # Interactive plot + p <- plot_ly(height = 750) |> + layout( + shapes = all_shapes, + annotations = all_annotations, + xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE, title = ""), + yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE, scaleanchor = "x", scaleratio = 1, title = ""), + showlegend = TRUE, + legend = list( + orientation = "h", + xanchor = "center", + x = 0.5, + y = -0.005, + yanchor = "top", + itemsizing = "constant" ), - translated_count = colDef( - name = "Translated Message Count", - defaultSortOrder = "desc", - cell = function(value) { - width <- paste0(value * 100 / max(complete_trans_df$translated_count), "%") - value <- format(value, big.mark = ",") - value <- format(value, width = 9, justify = "right") - bar <- div( - class = "bar-chart", - style = list(marginRight = "6px"), - div(class = "bar", style = list(width = width, backgroundColor = "#fc5185")) - ) - div(class = "bar-cell", span(class = "number", value), bar) - } - )), - compact = TRUE, - bordered = TRUE, - class = "categories-tbl" - ) + margin = list(t = 10, b = 80, l = 0, r = 0) + ) |> + add_trace( + data = hover_data, + x = ~real_x, + y = ~real_y, + type = 'scatter', + mode = 'markers', + color = ~category, + colors = colors, + text = ~paste("", language, "
", category, "messages:",Total, ""), + hoverinfo = "text", + name = ~category + ) + + return(p) +} + +build_waffle(lang_df) ``` -### Count of Untranslated Messages | Across Packages -```{r} -complete_untrans_df %>% - reactable( - ., - pagination = TRUE, - showPageSizeOptions = TRUE, - highlight = TRUE, - defaultSorted = "untranslated_count", - defaultColDef = colDef(headerClass = "header", align = "left"), - columns = list( - package = colDef( - name = "Package Name", - width = 150, - defaultSortOrder = "desc", - filterable = TRUE, - ), - language = colDef( - name = "Language", - width = 150, - filterable = TRUE, - ), - translated_count = colDef( - show = FALSE - ), - untranslated_count = colDef( - name = "Untranslated Message Count", - defaultSortOrder = "desc", - cell = function(value) { - width <- paste0(value * 100 / max(complete_untrans_df$untranslated_count), "%") - value <- format(value, big.mark = ",") - value <- format(value, width = 9, justify = "right") - bar <- div( - class = "bar-chart", - style = list(marginRight = "6px"), - div(class = "bar", style = list(width = width, backgroundColor = "#3fc1c9")) - ) - div(class = "bar-cell", span(class = "number", value), bar) - } - )), - compact = TRUE, - bordered = TRUE, - class = "categories-tbl" - ) -``` Row {data-height=450} ----------------------------------------------------------------------- @@ -230,7 +370,7 @@ final_df %>% bar <- div( class = "bar-chart", style = list(marginRight = "6px"), - div(class = "bar", style = list(width = value, backgroundColor = "#fc5185")) + div(class = "bar", style = list(width = value, backgroundColor = colors[["Translated"]])) ) div(class = "bar-cell", span(class = "number", value), bar) } @@ -243,7 +383,7 @@ final_df %>% bar <- div( class = "bar-chart", style = list(marginRight = "6px"), - div(class = "bar", style = list(width = value, backgroundColor = "#3fc1c9")) + div(class = "bar", style = list(width = value, backgroundColor = colors[["Untranslated"]])) ) div(class = "bar-cell", span(class = "number", value), bar) } @@ -256,7 +396,7 @@ final_df %>% bar <- div( class = "bar-chart", style = list(marginRight = "6px"), - div(class = "bar", style = list(width = value, backgroundColor = "#241327")) + div(class = "bar", style = list(width = value, backgroundColor = colors[["Fuzzy"]])) ) div(class = "bar-cell", span(class = "number", value), bar) } @@ -273,9 +413,9 @@ Row {data-height=100} ### Dashboard Updates ```{r} - gh_endpoint <- "https://api.github.com/repos/r-devel/translations-dashboard/commits?path=message_status.csv&page=1&per_page=1" - last_update_date <- get_last_data_update(gh_endpoint) - glue::glue("This page was last updated on: ", {last_update_date}) +gh_endpoint <- "https://api.github.com/repos/r-devel/translations-dashboard/commits?path=message_status.csv&page=1&per_page=1" +last_update_date <- get_last_data_update(gh_endpoint) +glue::glue("This page was last updated on: ", {last_update_date}) ``` @@ -285,7 +425,7 @@ R Translation Teams ===================================== -Row {data-height=450} +Row {data-height=850} ----------------------------------------------------------------------- ### R Translation Teams | Contact Details @@ -296,6 +436,7 @@ translation_teams %>% ., pagination = TRUE, showPageSizeOptions = TRUE, + defaultPageSize = 25, highlight = TRUE, defaultColDef = colDef(headerClass = "header", align = "left"), columns = list(