Challenges encountered in coding for an R data table that summarizes findings from various studies with collapsible subcategories

I am currently working on developing an interactive table that summarizes the top results from various studies and allows users to access more detailed information through child rows. The main table only displays the "top" model with the smallest p-value.

At the moment, I have divided the relevant data into two data frames: one for the top result and another for detailed results. I am combining these frames and nesting them based on the top results that need to be shown.

library(DT)
library(tidyr)
library(dplyr)
library(tibble)

# == Create dataframe with summarized results

allresults <- list(c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v1", "ageSex", 1e-6), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v2", "ageSexBmi", 0.001), 
                   ...
...

This code generates the desired summary table as a tibble, but I'm facing issues with the child row data not displaying when expanded:

https://i.sstatic.net/gcyPw.png

However, accessing the child rows programmatically shows that they contain the necessary data:

> data[data$outcome.bestOf=="Cancer", 'data'][[1]]
[[1]]
...

*** EDIT **** Below is the html from Chrome's inspect element option:


    <html><head>
    <meta charset="utf-8">
    <script src="lib/htmlwidgets-1.3/htmlwidgets.js"></script>
    ...

**** EDIT 2 **** With changes suggested by Stéphane Laurent

allresults <- list(c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v1", "ageSex", 1e-6), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v2", "ageSexBmi", 0.001), 
                   ...

Answer №1

We've identified two key issues:

d[",nested_columns,"]['cohort'].length

The problem here lies in the absence of a cohort column. It should be replaced with:

d[",nested_columns,"]['studyName'].length

Additionally, there's an issue with replacing dots with underscores:

var result = ('<table id=\"child_' + ",not_nested_columns_str," + '\">').replace('.','_') + '<thead><tr>'

This code snippet only replaces the first dot encountered. To address this, modify it to:

var result = ('<table id=\"child_' + ",not_nested_columns_str," + '\">').replace('/\\./g','_') + '<thead><tr>'

A similar correction is needed here as well:

var subtable = $(('table#child_' + ",not_nested_columns_str,").replace('.','_')).DataTable({

https://i.sstatic.net/Z9H95.gif

Complete code snippet for context:

library(DT)
library(tidyr)
library(dplyr)
library(tibble)

# Establish dataframe for summarizing results
allresults <- list(c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v1", "ageSex", 1e-6), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study1", "heartAttack_v2", "ageSexBmi", 0.001), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study2", "heartAttack_v1", "ageSex", 0.05), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study2", "heartAttack_v2", "ageSexBmi", "0.2"), 
                   c("HeartAttack", 1e-6, 0.05, 0.005, "study3", "heartAttack_v1", "ageSex", "0.005"), 
                   c( "Cancer",  0.05, 0.01, 0.002, "study1", "cancer_v1", "ageSex", 0.6), 
                   c( "Cancer",  0.05, 0.01, 0.002, "study1", "cancer_v2", "ageSex", 0.05), 
                   c("Cancer",  0.05, 0.01, 0.002, "study2", "cancer_v1", "ageSexBmi", 0.2), 
                   c("Cancer",  0.05, 0.01, 0.002, "study2", "cancer_v2", "ageSex", 0.01), 
                   c("Cancer",  0.05, 0.01, 0.002, "study3", "cancer_v1", "ageSexBmi", 0.002))

df <- as.data.frame(t(as.data.frame(allresults)))
colnames(df) <- c("outcome.bestOf", "study1.bestOf", "study2.bestOf", "study3.bestOf", "studyName", "outcome", "model", "pvalue")
rownames(df)<-NULL

# Collapse data for displaying top-result table with one row per outcome
nest_fields <- c("outcome.bestOf", "study1.bestOf", "study2.bestOf", "study3.bestOf") 
dt <- df %>%
  nest(-nest_fields)

# Add (+) column
data <- dt %>% {bind_cols(data_frame(' ' = rep('&oplus;',nrow(.))),.)}

# Access dynamic info and strings
# Source: https://github.com/rstudio/shiny-examples/issues/9

nested_columns         <- which(sapply(data,class)=="list") %>% setNames(NULL)
not_nested_columns     <- which(!(seq_along(data) %in% c(1,nested_columns)))
not_nested_columns_str <- not_nested_columns %>% paste(collapse="] + '_' + d[") %>% paste0("d[",.,"]")

# Callback function
callback <- paste0("
                   table.column(1).nodes().to$().css({cursor: 'pointer'});

                   // Convert nested table into formatted content
                   var format = function(d) {
                   if(d != null){ 
                   var result = ('<table id=\"child_' + ",not_nested_columns_str," + '\">').replace(/\\./g,'_') + '<thead><tr>'
                   for (var col in d[",nested_columns,"]){
                   result += '<th>' + col + '</th>'
                   }
                   result += '</tr></thead></table>'
                   return result
                   }else{
                   return '';
                   }
                   }

                   var format_datatable = function(d) {
                   var dataset = [];
                   for (var i = 0; i < + d[",nested_columns,"]['studyName'].length; i++) {
                   var datarow = [];
                   for (var col in d[",nested_columns,"]){
                   datarow.push(d[",nested_columns,"][col][i])
                   }
                   dataset.push(datarow)
                   }
                   var subtable = $(('table#child_' + ",not_nested_columns_str,").replace(/\\./g,'_')).DataTable({
                   'data': dataset,
                    'autoWidth': true, 
                      'deferRender': true, 
                      'info': false, 
                      'lengthChange': false, 
                      'ordering': true, 
                      'paging': false, 
                      'scrollX': false, 
                      'scrollY': false, 
                      'searching': false 
                   });
                   };

                   table.on('click', 'td.details-control', function() {
                   var td = $(this), row = table.row(td.closest('tr'));
                   if (row.child.isShown()) {
                   row.child.hide();
                   td.html('&oplus;');
                   } else {
                   row.child(format(row.data())).show();
                   td.html('&CircleMinus;');
                   format_datatable(row.data())
                   }
                   });"
                  )


# Display DataTable
datatable(
  data,
  escape = FALSE,
  options = list(
    columnDefs = list(
      list(visible = FALSE, targets = c(0,nested_columns) ), # Hide row numbers and nested columns
      list(orderable = FALSE, className = 'details-control', targets = 1) # turn first column into control column
    )
  ),
  callback = JS(callback)
)

Answer №2

Future-proofing Strategies

In light of the insightful response from @StéphaneLaurent, here are some key adjustments to ensure your code remains relevant in the year 2020:

  1. Given current standards, it is imperative that all inputs are explicitly named for nest(). Therefore, replace nest(-nest_fields) with nest(data=(-nest_fields))
  2. The use of data.frame() may trigger errors and should be substituted with tibble() in this instance:
    data <- dt %>% { bind_cols(data.frame(' ' = rep('&oplus;', nrow(.))), .) }
  3. The line
    nested_columns <- which(sapply(data,class)=="list") %>% setNames(NULL)
    requires modification due to a change in the class structure of nested tibbles. To accommodate for dual classes like "vctrs_list_of" and "vctrs_vctr", consider adding an additional sapply() as follows:
    nested_columns <- which(sapply(sapply(data,class), function(x) "vctrs_list_of" %in% x)) %>% setNames(NULL)


Addressing Unique Scenarios (For What It's Worth)

On a related note – after dedicating 3 hours to troubleshooting this issue – the method outlined above dynamically assigns distinct table ids in the JavaScript callback by combining all row values separated by underscores, such as:

"var result = ('<table id=\"child_' + ",not_nested_columns_str," + '\">').replace(/\\./g,'_') + '<thead><tr>'"

If any cell in a row contains a string with blank spaces, the assigned id will fail silently, resulting in incomplete child row display. To address this, consider introducing a unique ID column (id) in your original data frame and utilize it as the table id. This involves including the line

id_column <- which(names(data)=="id")
and adjusting the JS callback snippet accordingly:

"var result = ('<table id=\"child_' + d[",id_column,"] + '\">') + '<thead><tr>'"

It's also important to modify the JS callback section responsible for creating subtable based on the specified table id:

"var subtable = $(('table#child_' + d[",id_column,"])).DataTable({"

Note that if the id column exclusively contains numerical values, the need for the .replace() operation in JS diminishes.

Lastly, to exclude the ID column from the final output display, consider adding it to the options list like so:

list(visible = FALSE, targets = c(0,id_column,nested_columns) ), # Hide row numbers and nested columns`

These tweaks aim to streamline the process for others facing similar challenges, potentially saving valuable time and effort!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for converting Javascript require to Typescript import using the const keyword

Recently, I've been attempting to import faktory_worker_node from github.com/jbielick/faktory_worker. The README provides the following instructions: const faktory = require('faktory-worker'); faktory.register('ResizeImage', asyn ...

Puzzle involving unusual interactions with HTML, JS, and CSS scrollbars

I'm embarking on a special mission using CSS, HTML, and jQuery. My goal is to prevent scrolling when I hover over a specific element on the page. Right now, I'm accomplishing this by setting the body's overflow property to "hidden." However, ...

Inline-block list with consistent spacing between each item

I have a list of five items that are displayed inline. The challenge is to align the text in the first item with the left side and the text in the last item with the right side, while maintaining equal spacing between all items relative to both edges. Aft ...

Styling CSS for text enclosed in a paragraph element

I have a block of text formatted in the following way <div class="container"> <p style="text-align: center;"> <span style="text-decoration: underline;"> <strong> <img src="//cdn.shopify.co ...

Entering data into a specialized function designed for a shiny application in R programming

  Creating an app in Shiny to process data vectors and generate four types of plots (two heat maps, a point plot, and a semivariogram). Struggling to pass input data through the function for plotting. Seeking help with integrating UI inputs into the func ...

JavaScript code to generate a random color for the box shadow effect

Recently, I developed a function that generates random divs containing circles. The function randomly selects a border color for each circle, and this feature is functioning correctly. To enhance the appearance, I decided to add a box shadow to the circl ...

Ways to enable automatic scrolling of a page as the content expands (Utilizing collapsible elements)

For a recent project I've been working on, I decided to include 4 collapsible text boxes. However, I encountered an issue where opening content1 would expand and push down content2-4, requiring the user to manually scroll to view the remaining collaps ...

Cannot utilize the subscribed output value within the filter function

I am in need of assistance with my Angular 7 project. I have successfully implemented a service to call a Json file and output an object array. However, I am facing an issue when trying to filter the objects in the array based on a specific property called ...

Is the javascript function I created not recognized as "a function"?

A small .js file containing 3 functions for easy in-site cookie management was created. Below is the source code: // Create Cookie function Bake(name,value) { var oDate = new Date(); oDate.setYear(oDate.getFullYear()+1); var oCookie = encodeURIComponent(n ...

Utilizing JavaScript within the Spring MVC form tag

Can you please assist me with the following question? I am currently working on a project using JSP, where we are utilizing Spring form tags. My issue involves creating two radio buttons that, when clicked, will display different options and pass the sele ...

Discover results while inputting in the search box

Can anyone assist me? I'm looking to enhance my current code by adding a search functionality to the ul list. I want users to be able to type in a search term and have the matches automatically highlighted as they type, similar to a "find-as-you-type ...

Improving the quality of shadows in Three.js

I'm looking to create realistic shadows in my scene using a DirectionalLight to simulate sunlight. However, I'm struggling with the shadow quality settings - toggling between on/off, Low, Normal, and High: Setting parameters a and b within these ...

"Is there a way to dynamically add an input value as a class to the currently selected element using jQuery

Hey everyone, I'm currently working on some jQuery code to change the class of an icon by selecting a radio input with the corresponding class value. However, I'm encountering an issue where the class value is being added to all other icons as we ...

What is the process for incorporating a custom attribute in Quasar?

My goal is to include custom properties in the Quasar framework, but I am encountering an error with ESLint. It displays the following message: Array prototype is read only, properties should not be added I am looking to implement an extend method for Arr ...

Why is it that consolidating all my jQuery plugins into one file is ineffective?

Prior to this, I included the following scripts: <script type="text/javascript" src="{{MEDIA_URL}}js/plugins/json2.js"></script> <script type="text/javascript" src="{{MEDIA_URL}}js/plugins/jquery-msdropdown/js/jquery.dd.js"></script&g ...

Choose ng-change within the table

I've searched everywhere for an answer to this, but I couldn't find it. I have a table that contains select and date input fields. <table id="tblCorrAction" class="table table-bordered table-striped table-hover table-condensed"> <t ...

Transferring Object Information from AJAX to PHP

When attempting to send data to a PHP file for database storage, I am not receiving any response. If a checkbox is checked, the [obj][idCheckbox] value is set to 1; otherwise, it is set to 0. This is the file responsible for sending the data: var i=0; v ...

Name is the only piece of information that does not get stored in the

I'm struggling with my AJAX script that sends data to the database. Everything goes into the database except for $name and $n. My code is too long to share here, but I would really appreciate some help as my final year project submission deadline is a ...

Changing the Size of React Bootstrap Cards to Fit Your Grid Layout with Custom CSS

I am facing an issue with the varying sizes of react-bootstrap cards within a grid display. Check out the problem I am encountering: https://i.sstatic.net/szHjI.png I need the size of Over Under 0.5 card to be different from the one for Match Winner, as ...

Sending data to a URL using jQuery/Ajax while keeping it hidden from web developers

I own a small online shopping basket where customers can add products. Below is my index.php file: ...<script type="text/javascript" src="function.js"></script> <a title="Add to basket" onclick="add_product_to_cart('apple',&apos ...