I would like to make a plotly graph on shiny, very simple... but i don't get it... it's a candlestick graph... I load data from yahoo finance, i put it in a list and i create a dataframe following what we want see... but it doesn't work, it load all except the graph with the sentence :
"First argument, data, must be a data frame or shared data"
library(shiny)
library(quantmod)
library(lubridate)
library(plotly)
library(dplyr)
trim<-Sys.Date()- months(3)
#floor_date(ajd,"month")
comp<-c("CAC 40","Total","Sanofi","BNP","LVMH","Airbus","Axa","L'Oreal","Air Liquide","Danone","Vinci","Schneider","Societe Generale","Kering","Orange")
ref<-data.frame("^FCHI","FP.PA","SAN.PA","BNP.PA","MC.PA","AIR.PA","CS.PA","OR.PA","AI.PA","BN.PA","DG.PA","SU.PA","GLE.PA","KER.PA","ORA.PA")
colnames(ref)<-comp
for (i in 1:length(comp)){
stock<-ref[1,i]
stock<-as.character(stock)
getSymbols(stock,src="yahoo",from=trim,to=Sys.Date())
}
for (i in 1:length(comp)){
ref[,i]<-as.character(ref[,i])
}
ref[,1]<-c("FCHI")
data<-list()
for (i in 1:length(comp)){
data[[i]]<-get(ref[,i])
}
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Top companies of CAC 40 Analysis"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
h1("Companies"),
selectInput("titre","Company:",
choice=colnames(ref)),
hr(),
helpText("Data from yahoo finance")
),
# Show a plot of the generated distribution
mainPanel(
h3("Evolution du cours"),
plotlyOutput("graph")
)
)
))
library(shiny)
library(quantmod)
library(lubridate)
library(plotly)
library(dplyr)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
sortie<-reactive({
compa<-input$titre
temp<-data.frame(Date=index(data[[compa]]),coredata(data[[compa]]))
colnames(temp)<-c("Date","Open","High","Low","Close","Volume","Adjusted")
})
output$graph <- renderPlotly({
plot_ly(sortie,x=sortie$Date,type="candlestick",
open=sortie$Open,close=sortie$Close,high=sortie$High,low=sortie$Low)
layout(title="Quaterly evolution")
})
})
If someone find something i made wrong...
Hi there wasa a couple of problems with your code
first the data was not a named list so I changed the line
temp<-data.frame(Date=index(data[[compa]]),coredata(data[[compa]]))
to
temp<-data.frame(Date=index(data[[which(compa == comp)]]),coredata(data[[which(compa == comp) ]]))
to get the right index of comnp
then you were not returning the data frame from sortie but rather the vector of the column names. I just added a call to temp at the end of sortie to fix this. The last thing Ryan already mentioned in his comment with the brackets after sortie. Below follows a working version of the server code. I haven't changed anything else.
function(input, output) {
Sortie<-reactive({
compa<-input$titre
temp<-data.frame(Date=index(data[[which(compa == comp)]]),coredata(data[[which(compa == comp) ]]))
colnames(temp)<-c("Date","Open","High","Low","Close","Volume","Adjusted")
temp
})
output$graph <- renderPlotly({
sortie <- Sortie()
plot_ly(sortie,x=sortie$Date,type="candlestick",
open=sortie$Open,close=sortie$Close,high=sortie$High,low=sortie$Low) %>%
layout(title="Quaterly evolution")
})
}
It was that but i added the names of companies in the list in ui code :
data<-list()
for (i in 1:length(comp)){
data[[i]]<-get(ref[,i])
}
names(data)<-comp
So after my original code works with that :
shinyServer(function(input, output) {
sortie<-reactive({
compa<-input$titre
temp<-data.frame(Date=index(data[[compa]]),coredata(data[[compa ]]))
colnames(temp)<-c("Date","Open","High","Low","Close","Volume","Adjusted")
temp
})
output$graph <- renderPlotly({
sortie<-sortie()
plot_ly(sortie,x=~Date,type="candlestick",
open=~Open,close=~Close,high=~High,low=~Low)%>%
layout(title="Quarterly evolution")
})
})
Related
I am trying to access the data frame created in one render function into another render function.
There are two server outputs, lvi and Category, in lvi I have created Data1 data frame and Category I have created Data2 dataframe. I want to select Data2 where Data1 ID is matching.
I am following the below steps to achieve my objective but I get error "Object Data1 not found".
My UI is
ui <- fluidPage(
# App title ----
titlePanel("Phase1"),
fluidPage(
column(4,
# Input: Select a file ----
fileInput("file1", "Import file1")
)
),
fluidPage(
column(4,
# Input: Select a file ----
fileInput("file2", "Import File2")
)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
dataTableOutput("lvi"),
dataTableOutput("category")
)
)
My server code is
server <- function(input, output) {
output$lvi <- renderDataTable({
req(input$file1)
Data1 <- as.data.frame(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
output$category <- renderDataTable({
req(input$file2)
Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
Data2 <- Data2[,c(2,8)]
Data2 <- Data2[Data1$ID == "ID001",]
})
}
shinyApp(ui, server)
Once a reactive block is done executing, all elements within it go away, like a function. The only thing that survives is what is "returned" from that block, which is typically either the last expression in the block (or, when in a real function, something in return(...)). If you think of reactive (and observe) blocks as "functions", you may realize that the only thing that something outside of the function knows of what goes on inside the function is if the function explicitly returns it somehow.
With that in mind, the way you get to a frame inside one render/reactive block is to not calculate it inside that reactive block: instead, create that frame in its own data-reactive block and use it in both the render and the other render.
Try this (untested):
server <- function(input, output) {
Data1_rx <- eventReactive(input$file1, {
req(input$file1, file.exists(input$file1$datapath))
as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
output$lvi <- renderDataTable({ req(Data1_rx()) })
output$category <- renderDataTable({
req(input$file2, file.exists(input$file2$datapath),
Data1_rx(), "ID" %in% names(Data1_rx()))
Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
Data2 <- Data2[,c(2,8)]
Data2 <- Data2[Data1_rx()$ID == "ID001",]
})
}
shinyApp(ui, server)
But since we're already going down the road of "better design" and "best practices", let's break data2 out and the data2-filtered frame as well ... you may not be using it separately now, but it's often better to separate "loading/generate frames" from "rendering into something beautiful". That way, if you need to know something about the data you loaded, you don't have to (a) reload it elsewhere, inefficient; or (b) try to rip into the internals of the shiny DataTable object and get it manually. (Both are really bad ideas.)
So a slightly better solution might start with:
server <- function(input, output) {
Data1_rx <- eventReactive(input$file1, {
req(input$file1, file.exists(input$file1$datapath))
as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
Data2_rx <- eventReactive(input$file2, {
req(input$file2, file.exists(input$file2$datapath))
dat <- as.dataframe(read_excel(input$file2$datapath, sheet = "Sheet1"))
dat[,c(2,8)]
})
Data12_rx <- reactive({
req(Data1_rx(), Data2_rx())
Data2_rx()[ Data1_rx()$ID == "ID001", ]
})
output$lvi <- renderDataTable({ req(Data1_rx()); })
output$category <- renderDataTable({ req(Data12_rx()); })
}
shinyApp(ui, server)
While this code is a little longer, it also groups "data loading/munging" together, and "render data into something beautiful" together. And if you need to look at early data or filtered data, it's all right there.
(Side note: one performance hit you might see from this is that you now have more copies of data floating around. As long you are not dealing with "large" data, this isn't a huge deal.)
I would like to use a Shiny app to load a file (tab-separated), dynamically create a checkboxGroupInput, after the loading of the file (using observeEvent) using the column headers, then subset the data frame that comes from the file based on the selected checkboxes. The data is then plotted using code I can't share right now.
All is working fine, apart from the last bit: subsetting the dataframe based on the selected checkboxes in checkboxGroupInput. The checkboxes all start selected, and the plot is created fine. If you un-select one of the checkboxes, the plot re-plots appropriately for a split second (so the subsetting is working fine) then the unselected checkbox re-selects itself and the plot goes back to the old plot.
This is the tiny problem I'm trying to solve, guessing it's one line of code. I'm assuming it's because of some reactivity that I don't understand and the checkbox constantly resetting itself.
Here is an example:
###
## Some functions I can't share
### Shiny app
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("MagicPlotter"),
# Sidebar
sidebarLayout(
sidebarPanel(
fileInput(inputId = "myInputID",
label = "Your .csv file",
placeholder = "File not uploaded"),
uiOutput("mylist"),
uiOutput("submitbutton")
),
# Show a plot
mainPanel(
verticalLayout(
plotOutput("myPlot"))
)
)
)
# Define server
server <- function(input, output) {
output$myPlot <- renderPlot({
inputfile <- input$myInputID
if(is.null(inputfile))
{return()}
mydataframe <- read.table(file=inputfile$datapath, sep="\t", head=T, row.names = 1)
mydataframecolumnnames <- colnames(mydataframe[1:(length(mydataframe)-1)])
# the last column is dropped because it's not relevant as a column name
observeEvent(input$myInputID, {
output$mylist <- renderUI({
checkboxGroupInput(inputId="mylist",
label="List of things to select",
choices=mydataframecolumnnames,
selected=mydataframecolumnnames)
})
})
observeEvent(input$myInputID, {
output$submitbutton <- renderUI({
submitButton("Subset")
})
})
mysubset <- mydataframe[input$mylist]
myPlot(mysubset)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Thanks all
I think there are a few things that might help...
One, you can move your observeEvent methods outside of your renderPlot.
Also, you can create a reactive function to read in the data table.
I hope this helps.
server <- function(input, output) {
myDataFrame <- reactive({
inputfile <- input$myInputID
if(is.null(inputfile))
{return()}
read.table(file=inputfile$datapath, sep="\t", head=T, row.names = 1)
})
output$myPlot <- renderPlot({
req(input$mylist)
mysubset <- myDataFrame()[input$mylist]
plot(mysubset)
})
observeEvent(input$myInputID, {
mydata <- myDataFrame()
mydataframecolumnnames <- colnames(mydata[1:(length(mydata)-1)])
output$mylist <- renderUI({
checkboxGroupInput(inputId="mylist",
label="List of things to select",
choices=mydataframecolumnnames,
selected=mydataframecolumnnames)
})
})
observeEvent(input$myInputID, {
output$submitbutton <- renderUI({
submitButton("Subset")
})
})
}
I developed a small shiny app:
app
The app plots the rain for stations that are chosen in the selectizeInput.
It goes to an external server for the data each time a station is add or removed.
At the moment, it fetches the data from an external server for all the stations regardless if they remain in the list or not. This adds time and computation that are not needed.
My question is how do I reduce the need to get data that is already present?
because I can't present the real app I created a reproducible app to illustrate my code flow:
#data
id <- as.numeric(1:26)
names(id) <- letters
#dataframe function
get.rain.data <- function(id){
print(id)
vec <- 1:100
id <- as.numeric(id)
print(id)
df <- do.call(rbind,lapply(id,function(i)
tibble(x=vec,y=vec*i+vec^2*i,
id=as.factor(rep(i,length(vec))))))
return(df)
}
#plot function
plot.rain <- function(df){
print(df)
p <- ggplot(df,aes(x=x,y=y,group=id))+
geom_line(aes(color=id),size=0.6)
ggplotly(p,height=700)
}
#### UI
ui <- fluidPage(
titlePanel(h1("Rain Intensities and Cumulative Rain")),
sidebarLayout(
sidebarPanel(
helpText("Check rain with info from
IMS.gov.il"),
selectizeInput("var", h3("Select station"),
choices = id,
multiple = T,
selected = 4)
),
mainPanel(
plotlyOutput("rain")
)
)
)
# Define server logic ----
server <- function(input, output) {
dataInput <- reactive({
get.rain.data(input$var)
})
output$rain <- renderPlotly({
req(input$var)
plot.rain(dataInput())
})
}
# Run the application
shinyApp(ui = ui, server = server)
You have the needed code. Everywhere you want to use results from input$var call DataInput() instead. By creating the reactive dataInput function, it will be called when the input$var is updated
# Define server logic ----
server <- function(input, output) {
dataInput <- reactive({
get.rain.data(input$var)
})
output$rain <- renderPlotly({
plot.rain(dataInput())
})
}
I think what you need is to cache values so that they are only queried once. You may want look at the memoise package the can automatically do this for you.
https://github.com/r-lib/memoise
I'm trying to make a shiny app to load some data from different API, to do directly some analysis like graph...
I searched on the website of shiny i didn't find a way. My data doesn't want to load on the graph, i think it's because i load data directly on the server page, because i want load only the data wanted... The data comes from the ecb package from european central bank, which load the data from their API. This my code :
UI
library(shiny)
#library(quantmod)
library(lubridate)
library(plotly)
library(ggplot2)
ti<-c("PIB","MM_M3","Taux_d_Inflation")
data<-data.frame("ICP.M.U2.N.000000.4.ANR","BSI.M.U2.Y.V.M30.X.I.U2.2300.Z01.A","MNA.Q.Y.I8.W2.S1.S1.B.B1GQ._Z._Z._Z.EUR.LR.GY")
colnames(data)<-ti
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Evolution Economique"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
h1("Indicateur Europe"),
selectInput("chiffre","Indicateur:",
choice=ti),
#downloadButton("downloadData", "Download"),
actionButton("go","Load"),
hr(),
helpText("Donnees Banque Centrale Europeenne")
),
# Show a plot of the generated distribution
mainPanel(
plotlyOutput("graph")
)
)
))
Server
library(shiny)
library(lubridate)
library(plotly)
library(ggplot2)
library(ecb)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
observeEvent(input[["go"]],handlerExpr = {
compa<-input$chiffre
compa<-as.character(compa)
temp<-data[[compa]]
temp<-as.character(temp)
temp<-data.frame(Date=ymd(as.character(get_data(temp)$obstime),"%Y-%m"),Valeur=get_data(temp)$obsvalue)
temp<-get_data(temp)
temp<-data.frame(Date=temp$obstime,Valeur=temp$obsvalue)
temp
})
output$graph <- renderPlotly({
plot_ly(temp,x=~Date,
y=~Valeur,type="scatter",mode="lines")
#layout(title="Quaterly evolution")
})
})
Your graph isnt aware of the temp object as its initiated locally within the observeEvent, try to use eventReactive instead:
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
temp <- eventReactive(input$go,{
req(input$chiffre)
compa<-input$chiffre
compa<-as.character(compa)
temp<-data[[compa]]
temp<-as.character(temp)
temp<-data.frame(Date=ymd(as.character(get_data(temp)$obstime),"%Y-%m"),Valeur=get_data(temp)$obsvalue)
temp<-get_data(temp)
temp<-data.frame(Date=temp$obstime,Valeur=temp$obsvalue)
temp
})
output$graph <- renderPlotly({
plot_ly(temp(),x=~Date,y=~Valeur,type="scatter",mode="lines")
#layout(title="Quaterly evolution")
})
})
I am trying to have multiple html outputs in my shiny App but it seems like it can only show one at a time.
My UI is:
# ui.R
shinyUI(
mainPanel(
tableOutput("view"),
plotOutput("view2")
))
And my server is:
# server.R
library(googleVis)
library(RMySQL)
shinyServer(function(input, output) {
datasetInput <- reactive({
"try2" = subset(try1, idCampaign == input$inputId)
})
output$view <- renderGvis({
gvisTable(datasetInput(),options=list(width=1000, height=270, col='blue'))
})
output$view2 <- renderGvis({
gvisScatterChart(datasetInput2())
})
})
in the output to view2 you use datasetInput2() , this should be datasetInput(). Here datasetInput() just represents a dynamic version of a dataframe, you can use it in as many functions as you want, there is no need to index it.
alternatively i think you can use the tabsetPanel to divide your main page into certain parts and assign output objects to each of your tabPanel.