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
}
}
}
Related
I've recently made a simple for loop that outputs the Max and Min of the past 5 prices and it works perfectly, creating 2 new columns showing MaxH and MinL:
for(i in 5:nrow(XBTUSD_df_s)){
XBTUSD_df_s$MaxH[i] = max(XBTUSD_df_s$Price[(i-(5-1)):i])
XBTUSD_df_s$MinL[i] = min(XBTUSD_df_s$Price[(i-(5-1)):i])
}
I then put this for loop into a function so that I can adjust how many prices I want the Max and Min to be based off like so (the print lines were added as a sanity check):
FindMaxMin = function(x){
for(i in x:nrow(XBTUSD_df_s)){
XBTUSD_df_s$MaxH[i] = max(XBTUSD_df_s$Price[(i-(x-1)):i])
XBTUSD_df_s$MinL[i] = min(XBTUSD_df_s$Price[(i-(x-1)):i])
print(XBTUSD_df_s$MaxH[i])
print(XBTUSD_df_s$MinL[i])
}
}
But after for example:
FindMaxMin(x = 10)
The console will spit out all the expected results but unlike the for loop by itself, my dataframe will not automatically add on the MaxH and MinL columns.
I've tried return() and I think most likely it is a global environment problem but can't seem to wrap my head around it.
Thanks in advance!
You need to return the object from the function and then assign it later:
FindMaxMin = function(x, XBTUSD_df_s){
for(i in x:nrow(XBTUSD_df_s)){
XBTUSD_df_s$MaxH[i] = max(XBTUSD_df_s$Price[(i-(x-1)):i])
XBTUSD_df_s$MinL[i] = min(XBTUSD_df_s$Price[(i-(x-1)):i])
print(XBTUSD_df_s$MaxH[i])
print(XBTUSD_df_s$MinL[i])
}
return (XBTUSD_df_s)
}
new = FindMaxMin(10, XBTUSD_df_s)
I'm needing to perform deep pagination using R and the solr package. SOLR 7.2.1 server, R 3.4.3
I can't figure out how to get the nextCursorMark from the resultant dataframe. I usually do this in Python but this is stumping me.
res <- solr_all(base = myBase, rows = 100, verbose=TRUE,
sort = "unique_id asc",
fq="*:*",
cursorMark="*"
)
I cannot get the nextCursorMark from the result. Any help would be appreciated.
I have noticed that if I add the nextCursorMark to pageDoc it will return the value if parsetype is set to json, but not dataframe. So I guess another part is - where is that value if you return a dataframe?
So I finally got a way to make this work. This is not optimal, the final solution is in the github issue referenced in the comment. But this works:
dat <-"http://yadda.com"
cM = "*"
done = FALSE
rowCount = 0
a <- data.frame()
while (!done)
{
Data <- solr_search(base = dat, rows = 100, verbose=FALSE,
sort = "unique_id asc",
fq="*:*",
parsetype="json",
cursorMark=cM,
pageDoc = "nextCursorMark"
)
if (cM == Data$nextCursorMark) {
done = TRUE
} else {
cM = Data$nextCursorMark
}
a <- append(x = a, Data$response$docs)
rowCount = rowCount + length(Data$response$docs)
print(rowCount)
}
I have a bunch of values I want to read in to an if statement in R. Namely:
year_1 , year_2
And so on.
I would like to use a for loop or a vectorisation method to test each one but I am not familiar with this in R as opposed to C++.
So I'd like to achieve something like:
for(i in 1:15) {
if(year_[i] !=NULL) {
count = count + 1
}
}
Not sure whether I am not searching for the right thing or whether R just doesn't do this sort of thing easily. I have used paste and a for loop successfully in the past to automatically name new variables but this I haven't got a hold of.
Update
Ok your answer seems to be on the right track. I should have been a bit more specific and say that I am reading the data from an excel file of parameters and using the data to produce plots. Different data sets will have different years active. The core of this problem is telling R how many years are active, starting from param$year_1 to param$year_15. So I am trying to actually read param$year_1 and so on for example, and basically check whether it is empty or not which will allow me to know how many years this particular data set is working with. When I tried mget(paste0("param$year_", 1:5))
it said the value was not found.
Update 2
I am sure the difficulty with this comes down to my description. But here is exactly what I want to produce but automated to a few lines as I know I will want to do similar operations like this is in the future. What the actual data is is irrelevant. This non automated version produces exactly what I want.
Non Automated Code
if(is.na(param$year_1[1]) == TRUE || param$year_1[1] == '') {
print("empty")
}
if(is.na(param$year_2[1]) == TRUE || param$year_2[1] == '') {
print("empty")
}
if(is.na(param$year_3[1]) == TRUE || param$year_3[1] == '') {
print("empty")
}
if(is.na(param$year_4[1]) == TRUE || param$year_4[1] == '') {
print("empty")
}
so on and so on until the final
if(is.na(param$year_15[1]) == TRUE || param$year_15[1] == '') {
print("empty")
}
It is such a simple thing to do in C++ but I have to learn it in R for the future.
It sounds like you have a list-like structure that contains names year_1, year_2, ..., year_15 and you want to check how many of these are null or have a missing first element. You could use standard indexing to limit to the elements for those years, sapply to check which are null, and sum to add up those values:
which(sapply(paste0("year_", 1:15), function(x) {
is.null(param[[x]]) || param[[x]][1] == ''
}))
# year_2 year_5 year_9 year_10 year_11 year_12 year_14 year_15
# 2 5 9 10 11 12 14 15
Data:
param <- list(ID = 1:10, year_1 = 1:5, year_2 = NULL, year_3 = 1:7, year_4 = 1:2, year_5 = NULL, year_6 = 14, year_7 = 1:3, year_8 = 1:9, year_9 = NULL, year_10 = NULL, year_11 = NULL, year_12 = NULL, year_13 = 1:7, year_14 = NULL, year_15 = NULL)
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
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.