diff --git a/NEWS.md b/NEWS.md index 8bef40e..b2ed7c7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,11 +10,37 @@ editor_options: 1 - use reactive instead of reactiveValues for datasets +## 2025.01.05-1 + +### Bug Fixes + +1 - **Metadata - object color_fn not found**: new icon for logical and color format (function data_color) applied only if there is valid (non NA) min and max values ([#4](https://github.com/lgschuck/spada/issues/4) + +2 - **Edit > Convert - error in preview complex variable convertion**: fixed converting complex to character in the preview given that gt table in opt_interactive does not show complex properly ([#5](https://github.com/lgschuck/spada/issues/5) + +3 - **Edit > Filter: error in filtering complex**: now only show/allow operators '== (Equal)', '!= (Not Equal)', 'Is NA (is.na)', 'Not NA (! is.na)', 'In (%in%)' and 'Not In (! %in%)' (same for character and factors) ([#6](https://github.com/lgschuck/spada/issues/6) + +4 - **Edit > Filter: accept blank value**: now the value must have length 1 or bigger ([#7](https://github.com/lgschuck/spada/issues/7) + +### Improvements + +1 - utils functions + +2 - page_config_module: correction of a typo + +3 - spada function + +* new background color in sidebar + +* new value boxes in Data > Highligths (rows, valid, unique, zeros) and better server side checking (returning None if absent) + +* new itens in navbar: Options > Documentation link and Github link + ## 2025.01.03-1 ### Bug Fixes -1 - Data Overview - after Edit only refresh if updat in rows or sample: fixed with insertion of buttons inside output$pD_over_gt. Avaliate use of reactive instead of reactiveValues for datasets. +1 - Data Overview - after Edit only refresh if updat in rows or sample: fixed with insertion of buttons inside output$pD_over_gt. Avaliate use of reactive instead of reactiveValues for datasets. ([#3](https://github.com/lgschuck/spada/issues/3)) ### Improvements diff --git a/R/page_config_module.R b/R/page_config_module.R index d0155b7..651967b 100644 --- a/R/page_config_module.R +++ b/R/page_config_module.R @@ -20,7 +20,7 @@ page_config_ui <- function(id) { ), plotOutput(ns('sample_plot')) )), card(card_body( - h4('Size input files'), + h4('Size of input files'), numericInput(ns('input_file_size'), 'Size in MB', 500, min = 0, step = 100), btn_task(ns('btn_file_size'), 'Apply', icon('check')) )) diff --git a/R/spada.R b/R/spada.R index d4dcc59..48fb237 100644 --- a/R/spada.R +++ b/R/spada.R @@ -73,6 +73,7 @@ spada <- function(...) { # page sidebar ---------------------------------------------------------- sidebar = sidebar( + bg = '#e3e3e4', open = F, accordion( open = T, @@ -116,7 +117,7 @@ spada <- function(...) { title = 'Factor Vars', value = textOutput('pD_var_factor_vars'), showcase = bs_icon('diagram-3'), - theme = 'bg-gradient-green-indigo' + theme = 'bg-gradient-green-blue' ), value_box( title = 'Date Vars', @@ -127,36 +128,61 @@ spada <- function(...) { ), layout_column_wrap( value_box( - title = "Var with most NA's", + title = "Rows", + value = textOutput('pD_n_rows'), + showcase = bs_icon('list'), + theme = 'bg-gradient-blue-purple' + ), + value_box( + title = "Most valid", + value = textOutput('pD_var_most_valid'), + showcase = bs_icon('list-check'), + theme = 'bg-gradient-indigo-yellow', + p('Number of valid:', textOutput('pD_var_most_valid_n_valid', inline = T)) + ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), + value_box( + title = "Most unique", + value = textOutput('pD_var_most_unique'), + showcase = bs_icon('fingerprint'), + theme = 'bg-gradient-indigo-green', + p('Number of unique:', textOutput('pD_var_most_unique_n_unique', inline = T)) + ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), + value_box( + title = "Most zeros", + value = textOutput('pD_var_most_zeros'), + showcase = bs_icon('0-circle'), + theme = 'bg-gradient-orange-indigo', + p('Number of zeros:', textOutput('pD_var_most_zeros_n_zeros', inline = T)) + ) |> tooltip("Showing 1, there may be ties.", placement = 'top') + ), + layout_column_wrap( + value_box( + title = "Most NA's", value = textOutput('pD_var_most_nas'), showcase = bs_icon('database-x'), theme = 'bg-gradient-red-indigo', - p(textOutput('pD_var_most_nas_n', inline = T), ' rows') - ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), - value_box( - title = "Var with biggest % of NA's", - value = textOutput('pD_var_biggest_perc_nas'), - showcase = bs_icon('percent'), - theme = 'light', - p(textOutput('pD_var_biggest_perc_nas_perc', inline = T), ' %') + p("Number of NA's:", textOutput('pD_var_most_nas_n', inline = T), ' rows') ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), value_box( - title = 'Var with max value', + title = 'Max value', value = textOutput('pD_var_max_value', inline = T), showcase = bs_icon('graph-up-arrow', placement = 'top'), + theme = 'bg-gradient-blue-green', + p('Max value:', textOutput('pD_max_value', inline = T)) + ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), + value_box( + title = "Min value", + value = textOutput('pD_var_min_value'), + showcase = bs_icon('graph-down-arrow'), theme = 'bg-gradient-pink-indigo', - p('Max value:', textOutput('pD_max_value', inline = T)), - hr(), - p(bs_icon('graph-down-arrow'), 'Var with min value'), - p(textOutput('pD_var_min_value', inline = T)), p('Min value:', textOutput('pD_min_value', inline = T)) ) |> tooltip("Showing 1, there may be ties.", placement = 'top'), value_box( - title = "Var with biggest size", + title = "Biggest size", value = textOutput('pD_var_biggest_size'), showcase = bs_icon('sd-card'), theme = 'bg-gradient-teal-indigo', - p(textOutput('pD_var_biggest_size_size', inline = T), 'Bytes') + p('Size:', textOutput('pD_var_biggest_size_size', inline = T), 'Bytes') ) |> tooltip("Showing 1, there may be ties.", placement = 'top') ) ) @@ -317,7 +343,7 @@ spada <- function(...) { card_footer( layout_column_wrap( btn_task('pE_btn_reset', 'Reset Dataset', icon('arrow-rotate-right')) |> - tooltip('Restore the original dataset to the Active dataset', placement = 'top'), + tooltip('Restore to previous state (before been set as the Active dataset)', placement = 'top'), btn_task('pE_btn_bkp', 'Create Backup', icon('cloud-arrow-up')) |> tooltip('Create a copy of the Active dataset', placement = 'top'), btn_task('pE_btn_restore', 'Restore Backup', icon('cloud-arrow-down')) |> @@ -335,7 +361,7 @@ spada <- function(...) { nav_panel( 'Exploratory', - icon = bs_icon('bar-chart-fill'), + icon = bs_icon('bar-chart-line'), card( full_screen = T, @@ -444,18 +470,31 @@ spada <- function(...) { ) ), ), # end of analysis menu - # page config ----------------------------------------------------------- + # menu options ---------------------------------------------------------- nav_menu( title = 'Options', page_config_ui('pC'), - # page exit ------------------------------------------------------------- + nav_item( + tags$a( + icon('book'), + 'Documentation', + href = 'https://lgschuck.github.io/spada/', + target = '_blank' + )), nav_panel( value = 'exit', title = 'Exit', - icon = bs_icon('x-square-fill') + icon = icon('person-walking-arrow-right') ), ), + nav_item( + tags$a( + icon('github'), + href = 'https://github.com/lgschuck/spada', + target = '_blank' + )), + nav_spacer(), # active dataset -------------------------------------------------------- nav_item('Active dataset:'), @@ -632,6 +671,51 @@ spada <- function(...) { output$pD_var_factor_vars <- renderText(sapply(df$df_active, is.factor) |> sum()) output$pD_var_date_vars <- renderText(sapply(df$df_active, is_date) |> sum()) + output$pD_n_rows <- renderText( + df$df_active |> nrow() |> f_num() + ) + output$pD_var_most_valid <- renderText( + if(df_metadata() |> filter(n_valid > 0) |> nrow() < 1) { 'None' + } else { + df_metadata() |> arrange(-n_valid) |> head(1) |> pull(var) + } + ) + + output$pD_var_most_valid_n_valid <- renderText( + if(df_metadata() |> filter(n_valid > 0) |> nrow() < 1) { '0' + } else { + df_metadata() |> arrange(-n_valid) |> head(1) |> pull(n_valid) |> f_num() + } + ) + + output$pD_var_most_unique <- renderText( + if(df_metadata() |> filter(n_unique > 0) |> nrow() < 1) { 'None' + } else { + df_metadata() |> arrange(-n_unique) |> head(1) |> pull(var) + } + ) + + output$pD_var_most_unique_n_unique <- renderText( + if(df_metadata() |> filter(n_unique > 0) |> nrow() < 1) { '0' + } else { + df_metadata() |> arrange(-n_unique) |> head(1) |> pull(n_unique) |> f_num() + } + ) + + output$pD_var_most_zeros <- renderText( + if(df_metadata() |> filter(n_zero > 0) |> nrow() < 1) { 'None' + } else { + df_metadata() |> arrange(-n_zero) |> head(1) |> pull(var) + } + ) + + output$pD_var_most_zeros_n_zeros <- renderText( + if(df_metadata() |> filter(n_zero > 0) |> nrow() < 1) { '0' + } else { + df_metadata() |> arrange(-n_zero) |> head(1) |> pull(n_zero) |> f_num() + } + ) + output$pD_var_most_nas <- renderText( { if(df_metadata() |> filter(n_nas > 0) |> nrow() < 1) { 'None' @@ -650,38 +734,32 @@ spada <- function(...) { } ) - output$pD_var_biggest_perc_nas <- renderText( - { - if(df_metadata() |> filter(perc_nas > 0) |> nrow() < 1) { 'None' - } else { - df_metadata() |> filter(perc_nas > 0)|> arrange(-perc_nas, -n_nas) |> - head(1) |> pull(var) } - } - ) - - output$pD_var_biggest_perc_nas_perc <- renderText( - { - if(df_metadata() |> filter(perc_nas > 0) |> nrow() < 1) { '0' - } else { - df_metadata() |> filter(perc_nas > 0)|> arrange(-perc_nas, -n_nas) |> - head(1) |> pull(perc_nas) * 100 } - } - ) - output$pD_var_max_value <- renderText( - df_metadata() |> arrange(-max) |> head(1) |> pull(var) + if(df_metadata() |> filter(!is.na(max)) |> nrow() < 1) { 'None' + } else { + df_metadata() |> arrange(-max) |> head(1) |> pull(var) + } ) output$pD_max_value <- renderText( - df_metadata() |> arrange(-max) |> head(1) |> pull(max) |> f_num(dig = 3) + if(df_metadata() |> filter(!is.na(max)) |> nrow() < 1) { '0' + } else { + df_metadata() |> arrange(-max) |> head(1) |> pull(max) |> f_num(dig = 3) + } ) output$pD_var_min_value <- renderText( - df_metadata() |> arrange(min) |> head(1) |> pull(var) + if(df_metadata() |> filter(!is.na(min)) |> nrow() < 1) { 'None' + } else { + df_metadata() |> arrange(min) |> head(1) |> pull(var) + } ) output$pD_min_value <- renderText( - df_metadata() |> arrange(min) |> head(1) |> pull(min) |> f_num(dig = 3) + if(df_metadata() |> filter(!is.na(min)) |> nrow() < 1) { '0' + } else { + df_metadata() |> arrange(min) |> head(1) |> pull(min) |> f_num(dig = 3) + } ) output$pD_var_biggest_size <- renderText( @@ -810,8 +888,10 @@ spada <- function(...) { session, 'pE_filter_operator', label = 'Operator', choices = - if(df$df_active[[input$pE_filter_vars_filter]] |> is.factor() | - df$df_active[[input$pE_filter_vars_filter]] |> is.character()){ + if(df$df_active[[input$pE_filter_vars_filter]] |> is.factor() || + df$df_active[[input$pE_filter_vars_filter]] |> is.character() || + df$df_active[[input$pE_filter_vars_filter]] |> is.complex() + ){ c('', '== (Equal)' = '==', '!= (Not Equal)' = '!=', @@ -837,8 +917,9 @@ spada <- function(...) { # filter rows observe({ - if(input$pE_filter_vars_filter == '' | input$pE_filter_operator == ''){ - msg('Choose a variable and an operator') + if(input$pE_filter_vars_filter == '' || input$pE_filter_operator == '' + || length(pE_filter_value_temp()) == 0){ + msg('Choose a variable, an operator and a value', 3) } else if(length(pE_filter_value_temp()) > 1 & input$pE_filter_operator %in% c('==', '!=', '>', '>=', '<', '<=')){ msg_error('Operator requires value of length 1') @@ -998,6 +1079,8 @@ spada <- function(...) { req(input$pE_convert_vars_sel) if(input$pE_convert_vars_sel %in% names(df$df_active)){ pE_convert_preview_df() |> + lapply(\(x) if(is.complex(x)) as.character(x) else x) |> + as.data.frame() |> gt() |> opt_interactive( use_sorting = F, diff --git a/R/utils.R b/R/utils.R index 04e0348..9b788f2 100644 --- a/R/utils.R +++ b/R/utils.R @@ -220,15 +220,28 @@ gt_info <- function(df){ 'POSIXct/POSIXt', 'POSIXlt/POSIXt'), 'calendar', class == 'factor', 'sitemap', class == 'raw', 'sd-card', - class == 'complex', 'info')] + class == 'complex', 'info', + class == 'logical', 'puzzle-piece')] - df |> - gt::gt() |> + df_gt <- df |> + gt::gt() + + # if all NA do nothing + if(!all(df$min |> is.na())){ + df_gt <- df_gt |> + gt::data_color(columns = 'min', palette = yl_palette) + } + + # if all NA do nothing + if(!all(df$max |> is.na())){ + df_gt <- df_gt |> + gt::data_color(columns = 'max', palette = pk_palette) + } + + df_gt |> gt::fmt_percent(columns = c('perc_valid', 'perc_unique', 'perc_zero', 'perc_nas')) |> gt::fmt_bytes(columns = 'size') |> gt::data_color(columns = 'size', palette = blue_palette) |> - gt::data_color(columns = 'min', palette = yl_palette) |> - gt::data_color(columns = 'max', palette = pk_palette) |> gt::data_color(columns = 'n_valid', palette = lg_palette) |> gt::data_color(columns = 'n_unique', palette = dg_palette) |> gt::data_color(columns = 'n_zero', palette = gray_palette) |> diff --git a/docs/news/index.html b/docs/news/index.html index 8e1494d..8acaf8a 100644 --- a/docs/news/index.html +++ b/docs/news/index.html @@ -54,13 +54,32 @@
1 - Data Overview - after Edit only refresh if updat in rows or sample: fixed with insertion of buttons inside output$pD_over_gt. Avaliate use of reactive instead of reactiveValues for datasets.
+1 - Metadata - object color_fn not found: new icon for logical and color format (function data_color) applied only if there is valid (non NA) min and max values (#4
+2 - Edit > Convert - error in preview complex variable convertion: fixed converting complex to character in the preview given that gt table in opt_interactive does not show complex properly (#5
+3 - Edit > Filter: error in filtering complex: now only show/allow operators ‘== (Equal)’, ‘!= (Not Equal)’, ‘Is NA (is.na)’, ‘Not NA (! is.na)’, ‘In (%in%)’ and ‘Not In (! %in%)’ (same for character and factors) (#6
+4 - Edit > Filter: accept blank value: now the value must have length 1 or bigger (#7
1 - utils functions
+2 - page_config_module: correction of a typo
+3 - spada function
+new background color in sidebar
new value boxes in Data > Highligths (rows, valid, unique, zeros) and better server side checking (returning None if absent)
new itens in navbar: Options > Documentation link and Github link
1 - Data Overview - after Edit only refresh if updat in rows or sample: fixed with insertion of buttons inside output$pD_over_gt. Avaliate use of reactive instead of reactiveValues for datasets. (#3)
+1 - export_file_module: separator order now semicolon as default
2 - new import_file_module: allows input csv and RDS files
3 - page_config_module: new visual and size of input file as parameter
@@ -73,18 +92,18 @@1 - Analysis page - q1 object not found: back to calculate q1 and q3. (#1)
2 - Metadata - Error in zeros count: now df_info function uses suna(x == 0) instead of length(x[x == 0]) (#2)
1 - utils functions
df_info now uses suna instead of length, this change fix errors and provide gain in speed.
deletion of format_color_bar and main_value_box functions given that they are now in use anymore
1 - General
Created zzz.R and inserted utils::globalVariables for global variables (check note)
Value boxes: resized to give more space for other elements
1 - ‘Edit’ Page > Convert
1 - utils functions
1 - New functionality: copy dataset (Data page)
2 - Config page now is a module
3 - New Some reactives now with bindCache
1 - gt cannot show complex in opt_interactive, now convert to char before apply gt function
1 - utils functions
change color in value boxes (to gray) for better looking
number of rows (value box) now with decimals
1 - utils functions
df_info: improvement in performance (something like half the time in big datasets - 1e6 rows)
new function: gt_info to generate metadata with gt package