Sorting the numbers when units are added - shiny

I am trying to add the units to numbers in the dataframe. But I see after formatting, sorting is not working as expected (since the column is now characters). I need to sort as per numbers only (Millions coming at last). But this is not happening
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("tab")
)
server <- function(input, output, session) {
format_numbers <- function (df, column_name){
df[[column_name]] <- ifelse(nchar(df[[column_name]]) <= 5, paste(format(round(df[[column_name]] / 1e3, 1), trim = TRUE), "K"),
paste(format(round(df[[column_name]] / 1e6, 1), trim = TRUE), "M"))
}
df <- data.frame(x = c(12345,35666,2646575,345))
df$x <- format_numbers(df, "x")
output$tab <- renderDT({
datatable(df,escape = F)
})
}
shinyApp(ui, server)

You can add a new column and sort by the original one :
library(shiny)
library(DT)
library(dplyr)
ui <- fluidPage(
DTOutput("tab")
)
server <- function(input, output, session) {
format_numbers <- function (df, column_name){
df[[column_name]] <- ifelse(nchar(df[[column_name]]) <= 5, paste(format(round(df[[column_name]] / 1e3, 1), trim = TRUE), "K"),
paste(format(round(df[[column_name]] / 1e6, 1), trim = TRUE), "M"))
}
df <- data.frame(x = c(12345,35666,2646575,345))
df$NewX = format_numbers(df, "x")
df <- df %>% arrange(x)
output$tab <- renderDT({
datatable((df %>% select(-x)),escape = F)
})
}
shinyApp(ui, server)

Related

Shiny Dashboard Not Refreshing

The dashboard below has two tabs. Data is refreshed on changing the parameter. The first tab is refreshing properly with change in parameter. The second tab is not refreshed even though the parameter is used with reactive function. The code is very basic with the minimum functionality for testing and demo
The problem is of interaction hence these components are required. Also if you see..from following perspective. 1) data portion will setup the problem 2) 2 tabs are created to show the issue 3) tabs has minimum data displayed to show the failure of refresh...I can say this as I have removed the portion of code which was not directly linked with the problem.
library(quantmod)
library(shiny)
library(dplyr)
library(purrr)
library(stringr)
get_data <- function(symbols = c("AAPL", "MSFT", "META", "ORCL",
"TSLA", "GOOG")) {
syms <- getSymbols(symbols, from = "2020/01/01",
to = Sys.Date(), periodicity = "daily")
map_dfr(syms, function(sym) {
raw_data <- get(sym)
raw_data %>%
as_tibble() %>% # as_tibble will convert to tibble
set_names(c("OPEN", "HIGH", "LOW", "CLOSE", "VOLUME", "ADJUSTED")) %>%
mutate(SYMBOL = sym,
DATE = index(raw_data)) %>%
select(SYMBOL, DATE, OPEN, HIGH, LOW, CLOSE, VOLUME, ADJUSTED)
})}
if (!exists("df_all")) {df_all <- get_data()}
df_rep_data <- tribble(~ RunDate, ~ ListStocks,
"2020-01-06", "AAPL, GOOG, TSLA",
"2021-01-04", "ORCL",
"2022-01-04", "META, MSFT") %>%
mutate(RunDate = as.Date(RunDate))
make_table <- function(symbol, dat = df_all) {
dat %>%
filter(SYMBOL == symbol) %>%
select(DATE, OPEN, HIGH, LOW, CLOSE, VOLUME) %>%
slice(1:5)}
symb_ui <- function(id) {
ns <- NS(id)
tagList(
tags$h4(textOutput(ns("symbol"))),
tableOutput(ns("table"))
)}
symb_server <- function(id, get_symbol_name) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$symbol <- renderText(get_symbol_name())
output$table <- renderTable(make_table(get_symbol_name()))
})}
OneStock_ui <- function(id) {
ns <- NS(id)
tagList(
tags$h4(textOutput(ns("OneStocksymbol"))),
tableOutput(ns("OneStocktable"))
)}
OneStock_server <- function(id, get_symbol_date) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$OneStocksymbol <- renderText(get_symbol_date())
output$OneStocktable <- renderTable(make_table(get_symbol_date()))
})}
ui <- fluidPage(
tabsetPanel(
tabPanel(
selectInput("run_date", "Run Date", df_rep_data %>% pull(RunDate)),
tags$h2(textOutput("date_output")),
tags$h3(textOutput("lst_symb_output")),
uiOutput("symbols_output")),
tabPanel(
textInput("OneStockChart_input",'OneStockAnalysis', value = 'MSFT'),
uiOutput("OneStockAnalysis_output"))
))
server <- function(input, output, session) {
handler <- list()
get_syms <- list()
get_syms_onestock <- list()
handler_onestock <- list()
output$date_output <- renderText(req(input$run_date))
output$lst_symb_output <- renderText({
df_rep_data %>%
filter(RunDate == req(input$run_date)) %>%
pull(ListStocks)
})
output$symbols_output <- renderUI({
symbols <- df_rep_data %>%
filter(RunDate == req(input$run_date)) %>%
pull(ListStocks) %>%
str_split(fixed(", ")) %>%
unlist()
syms <- vector("list", length(symbols)) %>%
set_names(symbols)
for (sym in symbols) {
local({
my_sym <- sym
syms[[my_sym]] <<- symb_ui(my_sym)
get_syms[[my_sym]] <<- reactive(my_sym)
handler[[my_sym]] <<- symb_server(my_sym, get_syms[[my_sym]])
})
}
tagList(syms)
})
output$OneStockAnalysis_output <- renderUI({
symbols_onestock <- list(req(input$OneStockChart_input)) %>%
unlist()
syms_onestock <- vector("list", length(symbols_onestock)) %>%
set_names(symbols_onestock)
for (sym_onestock in symbols_onestock) {
local({
my_sym_onestock <- sym_onestock
syms_onestock[[my_sym_onestock]] <<- symb_ui(my_sym_onestock)
get_syms_onestock[[my_sym_onestock]] <<- reactive(my_sym_onestock)
handler_onestock[[my_sym_onestock]] <<- symb_server(my_sym_onestock, get_syms_onestock[[my_sym_onestock]])
})
}
tagList(syms_onestock)
})}
shinyApp(ui = ui, server = server)

Any chance using input$radio button as argument in group_by

I have tried to use radio button as an argument in group_by. Since I'm new to Shiny with no JS script background so quite being blind in render/output. and how to adapt with normal R-code.
Please show me some useful document/example in applying input to normal R-code
(not as simple as what's shown in shiny- widget gallery)
dat <- read_csv("VN_MAT as of 202001.csv")
datasetInput <- reactive({
switch(input$radio3,
"A" = "PROD_MANUFACTURER, PROD_BRAND, MKT_SDESC",
"B" = "PROD_MANUFACTURER, PROD_LDESC, MKT_SDESC" )
})
dat_brand <- reactive({
dat %>%
data.frame() %>%
group_by(datasetInput()) %>%
summarise(PER_MAT.TY = round(sum(PER_MAT.TY),digit = 2), PER_MAT.YA = round(sum(PER_MAT.YA), digit
=2)) %>%
arrange(MKT_SDESC) %>%
data.frame() %>%
add_count(MKT_SDESC, wt = PER_MAT.TY) %>%
mutate("VALUE_SHARE_TY" = round(PER_MAT.TY/n, digit = 4)) %>%
select(-n) %>%
add_count(MKT_SDESC, wt = PER_MAT.YA) %>%
mutate("VALUE_SHARE_LY" = round(PER_MAT.YA/n, digit = 4)) %>%
select(-n) %>%
mutate("DIFF_SHARE_YA" = round(VALUE_SHARE_TY - VALUE_SHARE_LY, digit = 4)) %>%
mutate("VALUE_GROWTH" = round(PER_MAT.TY/PER_MAT.YA - 1, digit =4))
})
After trial & error, I can figure out the answer as following code
I have overcome it with using if + choice of code
server <- function(input, output, session){
library(shiny)
library(ggplot2)
library(tidyverse)
Principal <- c("a","a","a","a","b","b","b","b","c","c")
Value <- as.numeric(c(4,1,1,3,4,2,2,3,2,1))
g <- c("t1","t1","t1","t1","t1","t2","t2","t2","t2","t2")
b <- as.numeric(c(4,1,1,3,4,2,2,3,2,1))
df <- data.frame(Principal,Value,g,b)
output$plot <- renderPlot({
if(input$radio1 == 1){
df%>%
group_by(g,b) %>%
summarize(total = sum(Value)) %>%
ggplot(aes(x = total, y = b))+
geom_point()
}else{
df%>%
group_by(Principal,b) %>%
summarize(total = sum(Value)) %>%
ggplot(aes(x = total, y = b))+
geom_point()}
})
}
ui <- basicPage(
radioButtons(
inputId = "radio1",
label = "Radio1",
choices = c(1, 2)
),
plotOutput("plot")
)
shinyApp(ui = ui, server = server)

RStudio-Shiny code works line-by-line (Ctrl+Enter), but not with the "Run App" button

in RStudio the below Shiny code works fine if I run it using Ctrl+Enter, line-by-line. However, if I run the whole code using the "Run App" button it generates this error:
Error in ts(x) : 'ts' object must have one or more observations
I think it is due to "lambda" parameter but I cannot see why. Any help is appreciated.
The link for "data.csv" is https://www.dropbox.com/s/p1bhacdg8j1qx42/data.csv?dl=0
====================================
library(shiny)
library(shinydashboard)
library(plotly)
library(forecast)
df <- read.csv("data.csv")
demand <- ts(df$demand, start = c(1995, 1), frequency = 12)
lbd <- BoxCox.lambda(demand, lower=-5, upper=5)
m <- ar(BoxCox(demand,lambda=lbd))
fit_BC <- forecast(m, h=12, lambda=lbd)
ui <- dashboardPage(
dashboardHeader(title = "Plot"),
dashboardSidebar(disable = TRUE),
dashboardBody(fluidRow(column(width = 12, box(plotlyOutput("forecast_plots"),width = NULL))))
)
server <- function(input, output) {
output$forecast_plots <- renderPlotly({
autoplot(fit_BC)
})
}
shinyApp(ui, server)
==================================
autoplot() returns ggplot object. But your output$forecast_plots requires plotly object(with plotlyOutput() function).
Working code is like the following:
ui <- dashboardPage(
dashboardHeader(title = "Plot"),
dashboardSidebar(disable = TRUE),
dashboardBody(fluidRow(column(width = 12, box(plotOutput("forecast_plots"),width = NULL))))
)
server <- function(input, output) {
output$forecast_plots <- renderPlot({
autoplot(fit_BC)
})
}
ggplot objects can be easily converted with ggplotly function, but unfortunately converted plotly autoplot graph loses the forecasting region. You can verify it like:
ui <- dashboardPage(
dashboardHeader(title = "Plot"),
dashboardSidebar(disable = TRUE),
dashboardBody(fluidRow(column(width = 12, box(plotlyOutput("forecast_plots"),width = NULL))))
)
server <- function(input, output) {
output$forecast_plots <- renderPlotly({
ggplotly(autoplot(fit_BC))
})
}
Add
I found autoplotly library.https://terrytangyuan.github.io/2018/02/12/autoplotly-intro/
autoplotly() function can convert autoplot object to plotly object which is roughly correct.
library(shiny)
library(shinydashboard)
library(plotly)
library(forecast)
library(autoplotly)
df <- read.csv("c:/Users/010170283/Downloads/data.csv")
demand <- ts(df$demand, start = c(1995, 1), frequency = 12)
lbd <- BoxCox.lambda(demand, lower=-5, upper=5)
m <- ar(BoxCox(demand,lambda=lbd))
fit_BC <- forecast(m, h=12, lambda=lbd)
ui <- dashboardPage(
dashboardHeader(title = "Plot"),
dashboardSidebar(disable = TRUE),
dashboardBody(fluidRow(column(width = 12, box(plotlyOutput("forecast_plots"),width = NULL))))
)
server <- function(input, output) {
output$forecast_plots <- renderPlotly({
autoplotly(autoplot(fit_BC))
})
}
shinyApp(ui, server)
The forecast region can be seen with it, and hi/lo 80 % edge values are presented with mouse hover event.

shiny: add/remove time-series to dygraphs upon input values

I'm building a shiny app that would display in dygraphs a basic dataset and then offer an option to add new time series upon selecting the checkbox input. However, as I coded it now, I'm 'stuck' at the original dataset and unable to add/remove new content. Any hints how to solve this are very welcome, thanks.
library(shinydashboard)
library(dygraphs)
library(dplyr)
ui <-dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
useShinyjs(),
checkboxGroupInput(inputId = 'options',
label = 'Choose your plot(s)',
choices = list("mdeaths" = 1,
"ldeaths" = 2)
),
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
output$plot1 <- renderDygraph({
final_ts <- ldeaths
p <- dygraph(final_ts, main = 'Main plot') %>%
dygraphs::dyRangeSelector()
if(1 %in% input$options) {
final_ts <- cbind(final_ts, mdeaths)
p <- p %>%
dySeries('mdeaths', 'Male Deaths')
} else if(2 %in% input$options) {
final_ts <- cbind(final_ts, fdeaths)
p <- p %>%
dySeries('fdeaths', 'Female Deaths')
}
p
})
dygraphOutput('plot1')
})
}
shinyApp(ui, server)
I'd suggest to dynamically filter the data based on the user selection instead of dynamically adding/removing traces from the plot:
library(shinydashboard)
library(shinyjs)
library(dygraphs)
library(dplyr)
lungDeaths <- cbind(ldeaths, mdeaths, fdeaths)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
useShinyjs(),
selectizeInput(
inputId = "options",
label = "Choose your trace(s)",
choices = colnames(lungDeaths),
selected = colnames(lungDeaths)[1],
multiple = TRUE,
options = list('plugins' = list('remove_button'))
),
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
filteredLungDeaths <- reactive({
lungDeaths[, input$options]
})
output$plot1 <- renderDygraph({
p <- dygraph(filteredLungDeaths(), main = 'Main plot') %>%
dygraphs::dyRangeSelector()
if('mdeaths' %in% colnames(filteredLungDeaths())){
p <- dySeries(p, 'mdeaths', 'Male Deaths')
}
if('fdeaths' %in% colnames(filteredLungDeaths())){
p <- dySeries(p, 'fdeaths', 'Female Deaths')
}
p
})
dygraphOutput('plot1')
})
}
shinyApp(ui, server)

Shiny: calculate cumsum based on dygraphs' RangeSelector

I'm building a shiny app where I want to plot a dataset with one of the variables being a cumulative sum of another variable. The latter needs to be re-calculated every time the start date of dygraphs' dyRangeSelector changes. Below is a basic code without cumsum calculations. Commented out code is what I tried, with no success.
library(shinydashboard)
library(stringr)
library(zoo)
library(dplyr)
library(dygraphs)
ui <-dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
uiOutput("Ui1")
)
)
server <- function(input, output, session) {
output$Ui1 <- renderUI({
# date range observer
# values <- reactiveValues()
#
# observeEvent(input$plot1_date_window, {
# from <- as.Date(str_sub(input$plot1_date_window[[1]], 1, 10))
# })
## dygraphs plot
output$plot1 <- renderDygraph({
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
# input_data <- m_df %>%
# filter(date >= values$from) %>%
# mutate(cumY = cumsum(Y))
input_xts <- xts(select(m_df, -date),
order.by = m_df$date)
#select(input_data, -date),
#order.by = input_data$date)
p <- dygraph(input_xts) %>%
dyRangeSelector()
p
})
## outputs
dygraphOutput('plot1')
})
}
shinyApp(ui, server)
UPDATE
I modified #Pork Chop's answer to be able to plot the cumulative values with other metrics on one graph, but I'm not even able to display the plot now:
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1'),
textOutput("cumsum1")
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
subdata <- reactive({
cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
})
output$plot1 <- renderDygraph({
req(input$plot1_date_window)
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
subdata_xts <- xts(select(subdata(), - date), order.by = subdata()$date)
final_xts <- cbind(input_xts, subdata_xts)
dygraph(final_xts) %>%
dyRangeSelector()
})
output$cumsum1 <- renderText({
req(input$plot1_date_window)
subdata <- cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
subdata
})
}
shinyApp(ui, server)
The problem with your updated code is, that you didn't keep the date information. Also once you start rendering a plot based on a change of the plot itself (recursion) it gets a little tricky. You have to make sure that re-rendering the plot doesn't trigger the rendering again or you'll end up in a loop. That's why I set retainDateWindow = TRUE. Besides that you don't want the plot to re-render right away after the first change of the slider that's why I debounced the subdata.
Nevertheless, using dygraphs you still have the problem, that when you add cumsum as a series your plot for dyRangeSelector is changed (y maximum of all series). Please see the following code:
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1')
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
subdata <- reactive({
if(!is.null(input$plot1_date_window)){
subdata <- m_df[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2]), ]
subdata$cumsum <- cumsum(subdata$Y)
subdata$Y <- NULL
} else {
subdata <- NULL
}
return(subdata)
})
subdata_d <- subdata %>% debounce(100)
output$plot1 <- renderDygraph({
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
if(is.null(subdata_d())){
final_xts <- input_xts
} else {
subdata_xts <- xts(select(subdata_d(), - date), order.by = subdata_d()$date)
final_xts <- cbind(input_xts, subdata_xts)
}
p <- dygraph(final_xts) %>% dySeries(name="Y") %>%
dyRangeSelector(retainDateWindow = TRUE)
if("cumsum" %in% names(final_xts)){
p <- dySeries(p, name="cumsum", axis = "y2")
}
p
})
}
shinyApp(ui, server)
Just as #PorkChop mentioned I'd recommend multiple outputs for this scenario. Furthermore, I'd suggest to have a look at library(plotly) and it's event_data().
This should do the job, I think it is cleaner to have separate outputs for your dashboard
library(xts)
library(shiny)
library(shinydashboard)
library(dygraphs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
dygraphOutput('plot1'),
textOutput("cumsum1")
)
)
server <- function(input, output, session) {
m_df <- data.frame(date=as.Date(zoo::as.yearmon(time(mdeaths))), Y=as.matrix(mdeaths))
output$plot1 <- renderDygraph({
input_xts <- xts(select(m_df, -date), order.by = m_df$date)
dygraph(input_xts) %>%
dyRangeSelector()
})
output$cumsum1 <- renderText({
req(input$plot1_date_window)
subdata <- cumsum(m_df$Y[m_df$date >= as.Date(input$plot1_date_window[1]) & m_df$date <= as.Date(input$plot1_date_window[2])])
subdata
})
}
shinyApp(ui, server)