Shiny Column rendering error - r

This is a Q on the Column rendering example (4.4)provided in this link.
http://rstudio.github.io/DT/options.html
I have implemented the example code described above to abbreviate character strings that are wider than 100 characters using the first 100 characters plus an ellipsis (…), and the full character string is displayed as a tooltip when you mouse over the cell. This works well as long as the column with custom rendering has full text in it. However, when it encounters an empty cell the table is not displayed and it shows " Processing..." on shiny browser. On disabling this custom rendering I am able to display the table with empty fields as expected.
Did anyone had similar issue, any suggestion to overcome this ?
Below is my custom column rendering code.
output$PM_output <- DT::renderDataTable(
expr = DT::datatable(PubmedOutput(PubmedSearch()),
class = 'cell-border stripe compact hover',
escape = F, selection = 'multiple',
options = list(
initComplete = JS("function(settings, json) {",
"$(this.api().table().header()).css({
'background-color': '#303030',
'color': '#FFFF00'});","}"),
autoWidth = T,
LengthMenu = c(5, 30, 50),
columnDefs = list(list(
targets = 6,
render = JS(
"function(data, type, row, meta) {",
"return type === 'display' && data.length > 100 ?",
"'<span title=\"' + data + '\">' +
data.substr(0, 100) + '...</span>' : data;", "}"))),
columnDefs = list(list(
targets = c(1:8),
className = 'dt-center')),
pageLength = 1, server = T)))
The code that generate the Column 6 that I have passed custom rendering on.
PM.ID <- c("26391251","26372702","26372699","26371045") # does not output table
fetch.pubmed <- entrez_fetch(db = "pubmed", id = PM.ID,
rettype = "xml", parsed = T)
abstracts = xpathApply(fetch.pubmed, '//PubmedArticle//Article', function(x) xmlValue(xmlChildren(x)$Abstract))
abstracts # ID 26372702, 26372699 has no abstract. and returns NA
Any inputs and suggestion.
P.S: Is there a better way to display data other than ellipsis/ tooltip ?
the code is too big to paste it all, hence picking only the parts where I noticed the issue. I hope it helps.

The condition data.length > 100 is not enough: you need to make sure data is a character string first. In your case, data may be null (converted from R's NA to JavaScript), and null.length will trigger an error. Replace
type === 'display' && data.length > 100
with a more rigorous condition:
type === 'display' && typeof data === 'string' && data.length > 100

Related

How to target specific columns with DT's SearchPanes extension

I want to implement DT's SearchPanes extension while explicitly including/excluding specific fields but am not sure how to accomplish it. I want all of the fields to show, but only select fields to be included in the SearchPanes interface.
In the reproducible example below (which is essentially from the documentation), how would I select just island, sex, and year for inclusion in SearchPanes?
I've tried different settings with searchPanes and the targets arguments, but I do not understand how to use these and I don't yet follow the JS documentation very well. Any guidance on how these work and how to select columns for inclusion would be much appreciated.
library(DT)
library(palmerpenguins)
datatable(
penguins,
options = list(dom = 'Pfrtip', columnDefs = list(list(
searchPanes = list(show = FALSE), targets = 1:4
))),
extensions = c('Select', 'SearchPanes'),
selection = 'none'
)
There may be a better way but this works:
datatable(
penguins,
options = list(
dom = 'Pfrtip',
columnDefs = list(
list(
searchPanes = list(show = FALSE), targets = c(1, 3:6)
),
list(
searchPanes = list(show = TRUE), targets = c(2, 7:9)
)
)
),
extensions = c('Select', 'SearchPanes'),
selection = 'none'
)
The searchPanes argument show can be set to TRUE or FALSE and the state is directed to specific target columns defined in the targets argument.
On one line, I set show=FALSE and defined all of the columns that I did not want showing. Then on the following line, I set showTRUE and defined the columns that I want showing. I found that if I set a column to show=FALSE and in the next line set it to show=TRUE it remains unshown.
The DataTables JS library documentation was helpful, but took a bit to understand. The section on columns.searchPanes.show contained the answer. Each searchPanes statement has some arguments and a set of targets. As follows:
$(document).ready(function() {
$('#example').DataTable({
dom: 'Plfrtip',
columnDefs: [
{
searchPanes: {
show: true
},
targets: [0]
},
{
searchPanes: {
show: false
},
targets: [2]
}
]
});
});

Best practices for drake pipeline experimentation

I'm new to drake but loving it so far. One thing I'm having trouble with is how to best go about experimenting with different pipeline configurations. That is, my plans consist purely of a chain of targets where the output from the first target is the input for the second, the second forms the input for the third, etc. My targets all have the same basic structure (dynamic targets with tibbles as individual entries) expected as input and supplied as output, and I want to experiment with different orderings, inclusion/exclusion of certain steps, etc. For example:
plan = drake::drake_plan(
a_transformed = target(
compute_a_transform(list_of_input_data)
, dynamic = map(list_of_input_data)
)
, b_transformed = target(
compute_b_transform(a_transformed)
, dynamic = map(a_transformed)
)
, c_transformed = target(
compute_c_transform(c_transformed)
, dynamic = map(c_transformed)
)
)
The way I've been using drake so far is that each target has a unique/meaningful name, so when I, for example, remove a target, I have to rename the input supplied to the subsequent target:
plan = drake::drake_plan(
a_transformed = target(
compute_a_transform(list_of_input_data)
, dynamic = map(list_of_input_data)
)
#, b_transformed = target(
# compute_b_transform(a_transformed)
# , dynamic = map(a_transformed)
#)
#note the b-transform step has been removed (commented-out), requiring inputs to c_transform to be changed from `b_transform` to `a_transform`
, c_transformed = target(
compute_c_transform(a_transformed) #had to rename things here
, dynamic = map(a_transformed) #and here
)
)
Would it be too much to hope that there's a better way of experimenting that doesn't require this manual commenting-out and renaming?
I worked out a method that is a bit of a hack but works for me. I simply add a skip argument to each function that triggers return of the input if TRUE:
compute_a_transform = function(x,skip=F){
if(skip){
return(x)
}
... #regular compute_a_transform stuff here
}
Then, when I want to skip a step in the processing chain, I simply set skip=TRUE without commenting-out or renaming anything
plan = drake::drake_plan(
a_transformed = target(
compute_a_transform(list_of_input_data)
, dynamic = map(list_of_input_data)
)
, b_transformed = target(
compute_b_transform(a_transformed, skip=TRUE) #skip=TRUE means the b-transform isn't actually applied
, dynamic = map(a_transformed)
)
, c_transformed = target(
compute_c_transform(c_transformed)
, dynamic = map(c_transformed)
)
)

Format number into K(thousand), M(million) in Shiny DataTables

I'm looking for a straight forward way to change the formatting of numbers into K,M in shiny dataTables. Preferably with something like formatCurrency. I don't want to write k, m functions to convert number into string in order to do the formatting as it makes it difficult to sort rows by value.
There's no built-in way to do this, but it's not too bad to write your own format function in JavaScript that doesn't break row sorting.
See Column Rendering in the DT docs for how to do this: https://rstudio.github.io/DT/options.html
And this will also help:
https://datatables.net/reference/option/columns.render
Here's an example of a custom thousands formatter that rounds to 1 decimal place:
library(DT)
formatThousands <- JS(
"function(data) {",
"return (data / 1000).toFixed(1) + 'K'",
"}")
datatable(datasets::rock, rownames = FALSE, options = list(
columnDefs = list(list(
targets = 0:1, render = formatThousands
))
))
Alternatively, if you want a non-JavaScript method, you could use the colFormat function used with the reactable package. Unfortunately, there is no automatic millions option but it's pretty easy to replicate if you divide the original data and add the labels on with colFormat.
Product <- c('Apples','Oranges','Pears')
Revenue <- c(212384903, 23438872, 26443879)
df <- data.frame(Product,Revenue)
df$Revenue_millions <- dfeg$Revenue/1000000
reactable(df,
showSortable = TRUE,
columns = list(
Revenue_millions = colDef(format = colFormat(prefix = "£", separators = TRUE,digits=1,suffix = "m"))))
The data should now sort correctly
If you are using DataTables, to get the data as Unit format i.e
10000 -> 10K
we can use render function
"render": function ( data ) {
if(data > 999 && data < 1000000) {
return data/1000+' K'
}
else if(data > 1000000){
return data/1000000+' M'
}
else{
return data
}
}
}

Column selection and further plotting of filtered data from datatable (DT) in Shiny

I have two questions about datatable (DT) in Shiny and
till this moment i could not find an any answer.
I would like to select column instead of a row in datatable -->
I have tried (as it was written on official website http://rstudio.github.io/DT/shiny.html):
datatable(..., selection = list(target = 'column'))
in my code::
datatable(data[, c("Datum", "Kunde", "Block.Nr.", "Toleranz",
"Kaliberschema")], class = 'cell-border stripe',
rownames=FALSE, filter="top", selection = list(target = 'column'), options = list(lengthChange = FALSE, columnDefs = list(list(width = '200px', targets = "_all"), list(bSortable = FALSE, targets = "_all"))), callback=JS("
//hide column filters for two columns
$.each([0, 1], function(i, v) {
$('input.form-control').eq(v).hide()});",
"var tips = ['Datum von..bis', 'Kunde', 'Block.Nr.',
'Toleranz +', 'Kaliberschema'],
header = table.columns().header();
for (var i = 0; i < tips.length; i++) {
$(header[i]).attr('title', tips[i]);}")) %>%
formatStyle("Datum", color = 'red', backgroundColor = 'lightyellow', fontWeight = 'bold')})
This code was not working at all, just got an error:
Error in match.arg(selection) : 'arg' must be NULL or a character vector
Than i have tried inside an options smthg like this:
options = list(target = 'column', lengthChange = FALSE, columnDefs = list(list(width = '200px', targets = "_all")...
It was as well not working...
Does anyone have any ideas??
2nd Thing is that i would lke to use this selected column to plot a line plot and histogram using ggplot.
Thanks in advance for any ideas
Are you using the latest development version of DT available from github or the 2015 v0.1 package release from CRAN? Your error indicates the latter; the selection options you have chosen might simply not be available. For installation from github, you may install the devtools package from CRAN and proceed via library(devtools);install_github("rstudio/DT"). Or even better: ask the authors when the package becomes available via CRAN, as this sort of confusion has come up elsewhere ...

DT conditional formatting for column

I need some help with conditional formatting for DT::datatable. I would like to highlight a couple of names in the following example by printing them in italics. The names which need to be highlighted are in a vector name.highlight <- c("ABC","JKL")
require(DT)
mydf <- data.frame(name=c("ABC","DEF","GHI","JKL","MNO","PQR"), value=1:6)
DT::datatable(mydf)
Based on what I see here and here, seems like I need to use render. I have no idea how to write the JS code or how I can pass in a vector/container with all the strings which need to be highlighted.
datatable(mydf, options = list(columnDefs = list(list(
targets = 0, render = JS("function(data, type, full, meta) {", ..., "}")
))))
Thanks.
datatable(mydf, options = list(columnDefs = list(list(
targets = 0, render = JS(
"function(data, type, full, meta) {",
"italic_words=['ABC','JKL']",
"return type === 'display' && italic_words.indexOf(data) != -1 ?",
"'<i>'+data+'</i>' : data;",
"}")
))))
I defined the italic_words variable in the javascript function. The variable contains an array of all the words you want in italic. Then I used the indexOf() javascript function. If the name isn't in the variable italic_words, this function will return -1, and the name will not be italicized.

Resources