I've just started at an internship where my first task is to improve a Shiny application by updating all existing ggplot graphs into Plotly graphs. I'm pretty new to R and Shiny, so I'm having a couple of issues getting started.
Currently, one of the graphs in this application are generated as follows:
output$barBoxPlot <- renderUI({
plotOutput("Barplot", width = 700, height = 300
, click = "plot_click"
, hover = "plot_hover"
, brush = "plot_brush")
})
Where "Barplot" is an outputId that corresponds to a ggplot graph generated in another part of the code.
I'm trying to plot this graph ("Barplot") as a Plotly graph, using the ggplotly() function, using something like this:
output$barBoxPlot <- renderPlotly({
ggplotly(<insert graph here>)
})
However, I cannot figure out how to pass in the "Barplot" parameter (which is an outputId) into ggplotly(). ggplotly takes in an instance of a ggplot graph, and not an outputId.
Is there any way to pass in an outputId into ggplotly()?
Thank you!
Would've put this in a comment but can't to that yet because of reputation:
There are multiple ways to solve this wihtout trying to pass an outputID to ggplotly().
In the reactive that is in the output$Barplot <- renderPlot(this_reactive_here()) , use ggplotly() directly (if you don't need the original output$barBoxPlot
Create a function or a reactive that takes a ggplot object and only does return(ggplotly(x)) , then put that into your renderPlotly()
EDIT for clarification on 2:
The Barplot that is in plotOutput should have a server entry that looks something like this:
output$Barplot <- renderPlot({
ggplot(data, aes(...)) # etc
})
Take the code inside and put it in a reactive, like this:
barplot_ggplot <- reactive({
ggplot(data, aes(...)) # etc
})
Then you can use it in the output$Barplot as barplot_ggplot() and in the renderPlotly() as ggplotly(barplot_ggplot()).
I hope that's a little bit clearer.
Related
My Shiny app is getting a little long, as I'm plotting a variety of graphs in a number of panels. Accordingly, to help with some of the organization, I was wondering if it was possible to move the code for the graphs into a separate r-script, and call those graphs from the original r script.
Adding some further complication, the graphs that I'd like to display all require user input from the Shiny app.
Is it possible to use code from another script in R to plot graphs, and, if so, how? Additionally, as there will be multiple graphs, is it possible to specify which graph from the new r-script will go in the designated location, or will I need to create a separate r-script for each graph (which would defeat the purpose of increased organizational oversight)?
I've written some simplified, reproducible code (see below) that I hope will give you an idea of what I'm looking for. Essentially, I'd like any code that produces a graph within renderPlot() to come from a separate r-script.
Many thanks for any help!
library(shiny)
ui <- fluidPage(
mainPanel(
selectInput("input1","Select an option",choices = c("First","Second")),
plotOutput("plot1"),
plotOutput("plot2")
)
)
server <- function(input, output, session) {
output$plot1 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot(1,main = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot(2,main = input$input1)
}
})
output$plot2 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot(1*rnorm(1,10,2),main = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot(2*rnorm(1,50,2),main = input$input1)
}
})
}
shinyApp(ui, server)
You can make a function that takes arguments for the plot that you make like the data and plot title and then passes these arguments to your code that creates the plot. For example, say the only thing that changes is x and the plot title, you can define a function that takes those arguments and then uses them in the code to make the plot. Then you save this in a separate script and call the script using source() in your shiny app.
plots.R
plot_data <- function(x, y=NULL, plot.title){
if(is.null(y)) {
y <- seq(from = 1, by = 1, length.out = length(x))
}
plot(x, y, main = plot.title)
}
Load the function into your global environment using source('plots.R'), make sure plots.R is saved in the same location as your shiny app.
library(shiny)
source("plots.R")
ui <- fluidPage(
mainPanel(
selectInput("input1","Select an option",choices = c("First","Second")),
plotOutput("plot1"),
plotOutput("plot2")
)
)
server <- function(input, output, session) {
output$plot1 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot_data(1, plot.title = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot_data(2, plot.title = input$input1)
}
})
output$plot2 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot_data(1*rnorm(1,10,2),plot.title = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot_data(2*rnorm(1,50,2),plot.title = input$input1)
}
})
}
shinyApp(ui, server)
Of course this doesn't look like much of a difference, but with complex plots that span multiple lines, turning your plot code into a function will turn multiple lines into just one.
I am using Shiny and ggplot2 for an interactive graph. I also used "plot1_click" to get x and y locations.
output$selected <- renderText({
paste0("Value=", input$plot1_click$x, "\n",
"Names=", input$plot1_click$y) }) #how to get names???
This is part of server code. Here what I want is, instead of printing the "y" coordinates, I want to print the corresponding name written in y-axis. Is there any possible way for it??
As far as I know clicking points is not supported in plotOutput. Click events will only return coordinates of the click location. Those coordinates can however be used to figure out the nearest point.
This shiny app from the shiny gallery pages uses the function shiny::nearPoints which does exactly that. Here is a minimal example.
library(shiny)
library(ggplot2)
shinyApp(
fluidPage(
plotOutput("plot", click = "plot_click"),
verbatimTextOutput('print')
),
server = function(input, output, session){
output$plot <- renderPlot({ggplot(mtcars, aes(wt, mpg)) + geom_point()})
output$print = renderPrint({
nearPoints(
mtcars, # the plotting data
input$plot_click, # input variable to get the x/y coordinates from
maxpoints = 1, # only show the single nearest point
threshold = 1000 # basically a search radius. set this big enough
# to show at least one point per click
)
})
}
)
The verbatimTextOutput shows you the nearest point to the clicked location. Notice that nearPoints only works with ggplots like that. But the help page suggests that there is also a way to use this with base graphics.
I want to plot a graph within a shiny app. Then I want to add multiple shades on the same graph. Before i show you my code let me define my sampe data.
dg= reactive ({dygraph(X1(), main ="interactive graph",
xlab = "time frame",
ylab = "records" ) %>% dyRangeSelector() })
# I have a table for the shades to be added, it's defined with reactive
shade_tab=reactive({ Panne[Panne$Equipement==input$machine,] })
# add shades
for( i in 1:nrow(shade_tab()))
{ dg()= reactive({
dyShading(dg(), from= shade_tab()$Date[i],
to = shade_tab()$Date[i] + 24*60*60 ,
color = 'black'
})
}
output$dygraph <- renderDygraph({ dg()() })
This is the code I tried to run, but it does not work. Any help will be greatly appreciated.
Reactive expressions must be called inside reactive environments. So shade_tab() will not work in that for since is outside a reactive environment. You could fix that, wrapping the forinside an observe.
The basics section at https://shiny.rstudio.com/articles/ explains this really well :)
I'm having some trouble creating interactive plots in shiny that facet my data.
Here's some code that shows what I want, but it uses ggplot2 which is not interactive.
library(shiny)
library(data.table)
library(ggplot2)
x <- 1:10000
dt <- data.frame(a = 1:100, b = sample(x,100,replace=T), c = sample(x,100,replace=T), d = sample(x,100,replace=T))
dt.molten <- melt(dt,id.vars="a")
ui <- fluidPage(
plotOutput("gplot")
)
server = function(input, output) {
output$gplot <- renderPlot({
ggplot(y.molten,aes(x = value)) +
geom_histogram(binwidth = 100000) +
facet_wrap( ~ variable,ncol = 1)
})
}
shinyApp(ui = ui, server = server)
In my actual app, the amount of facets varies, so I can't simply hard code in 3 separate plots using highcharter, ggvis,or plotly.
Ideally I'd like it to look something like this:
require(highcharter)
x <- stl(log(AirPassengers), "per")
hchart(x)
Except with histograms instead of time-series data.
The main issue is that the data i'm plotting stretches over like -3,000,000 to +3,000,000 with a high concentration around 0. This makes it hard to see the bars at the edges, so I'd like for users to be able to zoom into certain ranges of the plot without having to select it via some ui element.
I'm open to suggestions using any plotting method in R, although i'd like to stay away from rCharts.
EDIT: I did discover that using plotly::ggplotly almost achieved what I'm looking for, however it isn't very clean. I did g <- ggplot(*plot code*) then ggplotly(g). Works decent, but it'll take quite a bit of work to clean up I think.
I recently start building shiny app but I got stuck. Please help me.Thank you in advance
I am trying to create a bar chart to show the count for different type of cash and different term. This part, the code went well.
And I also want to create the box plot to show the numeric summary for different variables selected by the user. I created a selectInput called "metric" and then create a reactive called "metric1" in server.R. and then use "metric1" as the variables I selected to create box plot in server.R.
But it keep saying "cannot find the function "metric1". I don't know why it regards "metric1" as a function? it should be a vector-name of the variable selected by the user.
And if I use input$metric in ggplot to create box plot directly, it still say Error: " object 'input' not found". Why cannot find input? I have paste the code below. It is not a long code. And please help me!
library(shiny)
library(ggplot2)
cash <- read.csv("cash 042014-032015.csv")
cash$TERM <- as.numeric(cash$TERM)
shinyServer(function(input, output) {
dataset <- reactive({cash[cash$mapped_name %in% (input$model),]})
metric1 <- reactive({input$metric})
output$caption <- renderText({
input$model
})
output$countPlot <- renderPlot({
p <- ggplot(dataset(), aes(Incentive.Type, fill=factor(Incentive.Type))) + geom_bar()+ facet_grid(~TERM, margins=TRUE)+theme(axis.text.x = element_blank(),axis.ticks=element_blank(),legend.text = element_text(size=20))+guides(fill=guide_legend(title="Incentive Type"),title.theme=element_text(size=30))+scale_x_discrete(limits=c("Standard","Standard+Captive","Standard+Customer","Standard+Captive+Customer","Special","Special+Captive","Special+Customer","Special+Captive+Customer"))
print(p)
})
output$summaryPlot <- renderPlot({
p <- ggplot(dataset(),aes(factor(Incentive.Type), metric1()))+geom_boxplot()
print(p)
})
})
Here is the ui.R
library(shiny)
library(ggplot2)
dataset <- cash
shinyUI(
fluidPage(
# Give the page a title
titlePanel("Incentives by Model"),
# Generate a row with a sidebar
sidebarPanel(
checkboxGroupInput("model", "Select Models:",
choices=c("370Z","Altima","Armada","Crew","Cube","Frontier","GTR","Juke","Leaf",
"Maxima","Murano","NV","Other","Pathfinder","Quest","Rogue","Sentra","Titan","Versa","Xterra"),selected="Altima"),
selectInput("metric","Please select an option below:", choices=c("Dealer Commission Amount"="DLR_COMM_AMT", "Total Monthly Payment"="TOT_MO_PMT","Original Loan Amount"="ORIG_LN_AMT", "Rate"="RATE"),
selected="DLR_COMM_AMT"),
width=2
),
mainPanel(
h3(textOutput("caption", container=span)),
plotOutput("countPlot"),
plotOutput("summaryPlot")
)
))
Try changing metric1() in the second ggplot call to metric1. As in:
p <- ggplot(dataset(),aes(factor(Incentive.Type), metric1))+geom_boxplot()
Actually I think you will have to use something like:
p <- ggplot(dataset(),aes_string(factor("Incentive.Type"), "metric1"))+geom_boxplot()
In order to get it to see the value of your variable metric1 and properly interpret the use of string variables inside of ggplot.