Format date in Datatable output - r

library(DT)
seq_dates <- data.frame(dates = as.Date("2017-01-01") + 1:6 * 100)
datatable(seq_dates) %>% formatDate(1, "toDateString")
I get a datatable in viewer pane displaying dates in following format "Mon May 22 2017".
Q - How can I format date column as "MM-YY"
If I do,
dplyr::mutate(seq_dates, dates = format(dates, format = "%b-%Y")) %>%
datatable()
I get the required date format, but in this second case column sorting doesn't work (sorting is done on alphabets rather than dates.)
P.S - I'm implementing this on shiny.

Hi in these cases do I think the best solution is to add a dummy column with the dates in orginal format and have the dates column being sorted according to the values in the DUMMY column. This is in Datatable quite easily done. Example code below.
seq_dates <- data.frame(dates = as.Date("2017-01-01") + 1:6 * 100)
datatable(seq_dates %>% mutate(DUMMY = dates,dates = format(dates, format = "%b-%Y")),
options = list(
columnDefs = list(
list(targets = 1,orderData = 2),
list(targets = 2, visible = FALSE)
)
))

For what it's worth (and using formatDate), the best that I can do is as follows:
datatable(seq_dates) %>%
formatDate(
columns = 1,
method = "toLocaleDateString",
params = list(
'en-US',
list(
year = 'numeric',
month = 'numeric')
)
)
And this yields date values like 4/2017 and 10/2017.
I've tried to find these parameter options (in github and the original datatables documentation) but to no avail. The only example in DT uses the parameters of short, long and numeric.

Converting "%b-%y" "dates" to date format is not an easy thing as I could see...
If you're not too attached to displaying "%b-%y" format, the easy way is to use "%Y-%m" or "%y-%m" format and the filter will work just fine :
library(DT)
seq_dates <- as.data.frame(seq(Sys.Date() - 100, Sys.Date(), by = "m"))
seq_dates <- format(seq_dates, format = "%y-%m")
datatable(seq_dates)
#resulting in
#1 2017-02
#2 2017-03
#3 2017-04
#4 2017-05
#or
#1 17-02
#2 17-03
#3 17-04
#4 17-05

There is a render method that you can use:
datatable( ...
options = list(..
columnDefs = list(..
list(targets = c(1), render = JS(
"function(data, type, row, meta) {",
"return type === 'display' ? new Date(data).toLocaleString() : data;"))))

Related

How to display period class from lubridate in datatable from DT?

I have runtime data for various devices that can be widely different, ranging from a few minutes to several months that I would like to display in a datatable. So I thought the seconds_to_period function from lubridate provides a neat format to print this data. However, I seem unable to display it within a datatable from DT, which is what I want to do (within a shiny App).
Some example data:
library(lubridate)
library(DT)
names <- c("A","B","C","D","E","F")
timevec <- c(225,2250,22500,225000,2250000,22500000)
timevec <- seconds_to_period(timevec)
Writing this into a datatable without any formatting does not work as it only displays the seconds without considering the minutes/hours etc.:
##### This cuts off at the seconds -> useless
table <- data.frame(name = names, time = timevec)
my_table <- datatable(table)
Formatting the time column with formatDate also doesn't work since it is not a date or POSIXct object. I can print the desired format by typecasting it as a string, but then the sorting of the column doesn't work as it is sorted alphabetically:
##### This prints the period format, but sorting does not work
table <- data.frame(name = names, time = as.character(timevec))
my_table <- datatable(table)
and of course I could just print the total time in seconds, but as I said I find this very unintuitive to read:
##### This prints the seconds -> unintuitive to read
table <- data.frame(name = names, time = as.duration(timevec))
my_table <- datatable(table)
Any Ideas on how to achieve this or alternative suggestions how to intuitively display duration data?
solution by programming DT to sort a shown character column by a hidden numeric column via columnDefs
library(tidyverse)
library(lubridate)
library(DT)
names <- c("A", "B", "C", "D", "E", "F")
timevec_raw <- c(225, 2250, 22500, 225000, 2250000, 22500000)
timevec_period <- seconds_to_period(timevec_raw)
(table <- tibble(
name = names,
timenum = timevec_raw,
timechar = as.character(timevec_period)
)
)
my_table <- datatable(table,
options = list(
columnDefs = list(
list(
visible = FALSE, targets = 2
), # hide column 2 the numeric one
list(
orderData = c(2), # the ordering of column 3 comes from hidden column 2
targets = c(3)
)
)
)
)

How to add header and rownames to ts

if I print to console
AirPassengers
I is nicely formated with header and row names, why following code is not also siniliary formated?
as.ts(
read.zoo(
data.frame(
date = seq(Sys.Date()-365, Sys.Date(), by = "day"),
value = seq(1, 366)
)
)
)
When you use the read.zoo function, it resturns a zoo object, which is a type of character.
If you get rid of the function you get:
as.ts(
data.frame(
date = seq(Sys.Date()-365, Sys.Date(), by = "day"),
value = seq(1, 366)
)
)
You should get a time series object that is a matrix format
If you must use read.zoo
ts <- as.ts(
zoo::read.zoo(df)
) |> data.frame() |> setNames(names(df[2]))
)

How to specify a custom formatter function gt table grand summary?

I'm trying to use a custom formatter function to format grand summary rows in gt table.
in the example below I was trying to use seconds_to_period from lubridate but I get
the error "**Error in stop_if_not_gt(data = data) : **
require(tidyverse)
require(lubridate)
sp500 %>%
dplyr::filter(
date >= "2015-01-05" &
date <="2015-01-16"
) %>%
dplyr::arrange(date) %>%
dplyr::mutate(
week = paste0(
"W", strftime(date, format = "%V"))
) %>%
dplyr::select(-adj_close, -volume) %>%
gt(
rowname_col = "date",
groupname_col = "week"
) %>%
grand_summary_rows(
columns = vars(open, high, low, close),
fns = list(
min = ~min(.),
max = ~max(.),
avg = ~mean(.)),
formatter = fmt(fns=seconds_to_period),
use_seps = FALSE
)
I've tried some variations like formatter = fmt(columns=vars(min),fns=seconds_to_period) with no sucess.
Thanks
Since you didn't share the seconds_to_period function, my guess is you are trying a transformation/computation with a format function. As far as I know, that's not possible. formatter arg allows you to apply a format to an already computed summary cell. And the sintaxys to pass the fmt* arguments inside grand_summary_rows is quite different. Instead of passing them inside parenthesis fmt* function, you should pass them as grand_summary_rows arguments:
df |>
gt()|>
grand_summary_rows(
columns = vars(open, high, low, close),
fns = list(
min = ~min(.),
max = ~max(.),
avg = ~mean(.)),
formatter = fmt_number,
decimals = 1,
use_seps = FALSE
)
In any case, in your code you're passing use_steps, which is a fmt_number argument, to a fmt function, which does not admit it. Take a look at fmt docummentation.
Anyway, it's not clear what you a are trying to accomplish. OHLC are prices data. And I guess from your function name (seconds_to_period) that you're trying to give this prices data a time class format. If the case, you should compute/transform the content before trying to format it.

create date vector, change to factor and format

I have the following code:
gsub("-","/",paste(cut(seq(as.POSIXct(Sys.Date(),format="%d-%b-%y"), by = "-1 day", length.out = 10),"days"),collapse = ","))
The output:
"2019/03/20,2019/03/19,2019/03/18,2019/03/17,2019/03/16,2019/03/15,2019/03/14,2019/03/13,2019/03/12,2019/03/11"
However the desired result is
'20/03/2019','19/03/2019','18/03/2019','17/03/2019','16/03/2019','15/03/2019','14/03/2019','13/03/2019','12/03/2019','11/03/2019'
How can I accomplish that ?
Regards
Not sure what you are trying to do but you can generate the required output by doing
format(Sys.Date() - 1:10, "%d/%m/%Y")
#[1] "20/03/2019" "19/03/2019" "18/03/2019" "17/03/2019" "16/03/2019" "15/03/2019"
# "14/03/2019" "13/03/2019" "12/03/2019" "11/03/2019"

How to get the grouping right in R with Plotly

I have some problem to group my data in Plotly under R. To start with I was using local data from a csv file, reading them with:
geogrid_data <- read.delim('geogrid.csv', row.names = NULL, stringsAsFactors = TRUE)
and the plotting went well, using the following:
library(plotly)
library(RColorBrewer)
x <- list(
title = 'Date'
)
p <- plotly::plot_ly(geogrid_data,
type = 'scatter',
x = ~ts_now,
y = ~absolute_v_sum,
text = paste('Table: ', geogrid_data$table_name,
'<br>Absolute_v_Sum: ', geogrid_data$absolute_v_sum),
hoverinfo = 'text',
mode = 'lines',
color = list(
color = colorRampPalette(RColorBrewer::brewer.pal(11,'Spectral'))(
length(unique(geogrid_data$table_name))
)
),
transforms = list(
list(
type = 'groupby',
groups = ~table_name
)
)
) %>% layout(showlegend = TRUE, xaxis = x)
Here the output:
Then I was going to alter the data source to an Oracle database table, reading the data as follows, using the ROracle package:
# retrieve data into resultSet object
rs <- dbSendQuery(con, "SELECT * FROM GEOGRID_STATS")
# fetch records from the resultSet into a data.frame
geogrid_data <- fetch(rs)
# free resources occupied by resultSet
dbClearResult(rs)
dbUnloadDriver(drv)
# remove duplicates from dataframe (based on TABLE_NAME, TS_BEFORE, TS_NOW, NOW_SUM)
geogrid_data <- geogrid_data %>% distinct(TABLE_NAME, TS_BEFORE, TS_NOW, NOW_SUM, .keep_all = TRUE)
# alter date columns in place
geogrid_data$TS_BEFORE <- as.Date(geogrid_data$TS_BEFORE, format='%d-%m-%Y')
geogrid_data$TS_NOW <- as.Date(geogrid_data$TS_NOW, format='%d-%m-%Y')
and adjusting the plotting to:
p <- plotly::plot_ly(
type = 'scatter',
x = geogrid_data$TS_NOW,
y = geogrid_data$ABSOLUTE_V_SUM,
text = paste('Table: ', geogrid_data$TABLE_NAME,
'<br>Absolute_v_Sum: ', geogrid_data$ABSOLUTE_V_SUM,
'<br>Date: ', geogrid_data$TS_NOW),
hoverinfo = 'text',
mode = 'lines',
color = list(
color = colorRampPalette(RColorBrewer::brewer.pal(11,'Spectral'))(
length(unique(geogrid_data$TABLE_NAME))
)
),
transforms = list(
list(
type = 'groupby',
groups = geogrid_data$TABLE_NAME
)
)
) %>% layout(showlegend = TRUE, xaxis = x)
Unfortunately, this is leading to some problem with the grouping as it seems.:
As you can see from the label text when hovering over the data point, the point represents data from NY_SKOV_PLANTEB_MW_POLY while the legend is set to show data from NY_BYGN_MW_POLY. Looking at other data points in this graph I found a wild mix of points of all sorts in this graph, some of them representing data of NY_BYGN_MW_POLY, most of them not.
Also the plotting with respect to the time line does not work any more, e.g. data are plotted with start on Dec. 11 - Dec. 10 - Dec. 10 - Dec. 12 - Dec. 20 - Dec. 17 - Dec. 16 - Dec. 15.
Where do I go wrong in handling the data, and what do I have to do to get it right?
Of course, one should look at the data... thanks Marco, after your question I did look at my data.
There are some points where I simply assumed things.
The reason why all data plotted fine with data from the csv file is simple. All information manually compiled in the csv file came from information in emails that have been ordered by date. Hence, I compiled the data in the csv file ordered by date and Plotly does not have any problems grouping the data by table_name.
After looking at my data I tidied up, keeping only the data I need to show in the plot and used dplyr to sort the data by time.
geogrid_data <- dplyr::arrange(geogrid_data, TS_NOW)
It is only by time and not by time and table name because the sorting by table name is done anyway by Plotly and the groupby statement

Resources