I expanded the result from my last question with a new idea.
Error in Running R Shiny App: Operation not allowed without an active reactive context
This time in addition to clustered points in Iris data (see my previous question), I want to show the regression line (on the plot), slope & intercept (on the sidebar) for the selected points as in:
The regression code is available here (separate server.R and ui.R files):
library(shiny)
shinyServer(function(input, output) {
model <- reactive({
brushed_data <- brushedPoints(iris, input$brush1,
xvar = "Petal.Length", yvar = "Petal.Width")
if(nrow(brushed_data) < 2){
return(NULL)
}
lm(Petal.Width ~ Petal.Length, data = brushed_data)
})
output$slopeOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][2]
}
})
output$intOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][1]
}
})
output$plot1 <- renderPlot({
plot(iris$Petal.Length, iris$Petal.Width, xlab = "Petal.Length",
ylab = "Petal.Width", main = "Iris Dataset",
cex = 1.5, pch = 16, bty = "n")
if(!is.null(model())){
abline(model(), col = "blue", lwd = 2)
}
})
})
and
library(shiny)
shinyUI(fluidPage(
titlePanel("Visualize Many Models"),
sidebarLayout(
sidebarPanel(
h3("Slope"),
textOutput("slopeOut"),
h3("Intercept"),
textOutput("intOut")
),
mainPanel(
plotOutput("plot1", brush = brushOpts(
id = "brush1"
))
)
)
))
I used the following code. However, I have a problem with merging these two ideas and the plot is not shown:
Here is the main code for this question (server and ui in one file):
# Loading Libraries and data
library(shiny)
library(caret)
library(ggplot2)
data(iris)
ui <- pageWithSidebar(
# heading 1
headerPanel(h1("Clustering Iris Data")),
sidebarPanel(
sliderInput("k", "Number of clusters:",
min = 1, max = 5, value = 3),
sliderInput("prob", "Training percentage:",
min=0.5, max=0.9, value = 0.7),
# bold text
tags$b("Slope:"),
textOutput("slopeOut"),
# empty line
br(),
# bold text
tags$b("Intercept:"),
textOutput("intOut")
),
# Enabling the submit button disables the hovering feature
# submitButton("submit")),
mainPanel(
# img(src='iris_types.jpg', align = "center", height="50%", width="50%"),
plotOutput("plot1",
click = "plot_click",
brush = brushOpts(id = "brush1")
),
verbatimTextOutput("info")
)
)
#----------------------------------------------------------------------------
server <- function(input, output) {
# the clustering part
get_training_data <- reactive({
inTrain <- createDataPartition(y=iris$Species,
p=input$prob,
list=FALSE)
training <- iris[ inTrain,]
testing <- iris[-inTrain,]
kMeans1 <- kmeans(subset(training,
select=-c(Species)),
centers=input$k)
training$clusters <- as.factor(kMeans1$cluster)
training
})
#-------------------------
# the linear model part
model <- reactive({
brushed_data <- brushedPoints(iris, input$brush1,
xvar = "Petal.Length", yvar = "Petal.Width")
if(nrow(brushed_data) < 2){
return(NULL)
}
lm(Petal.Width ~ Petal.Length, data = brushed_data)
})
# reactive
output$slopeOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][2]
}
})
# reactive
output$intOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][1]
}
})
#------------------------------------------------
# if (x()<4) 1 else 0
output$plot1 <- reactive({
if(is.null(model())) {
# If no regression model exists, show the regular scatter plot
# with clustered points and hovering feature
renderPlot({
plot(Petal.Width,
Petal.Length,
colour = clusters,
data = get_training_data(),
xlab="Petal Width",
ylab="Petal Length")
})
output$info <- renderPrint({
# With ggplot2, no need to tell it what the x and y variables are.
# threshold: set max distance, in pixels
# maxpoints: maximum number of rows to return
# addDist: add column with distance, in pixels
nearPoints(iris, input$plot_click, threshold = 10, maxpoints = 1,
addDist = FALSE)
})
# closing if
}
else
# If there is a regression model, show the plot with the regression line for the brushed points
renderPlot({
plot(Petal.Width,
Petal.Length,
colour = clusters,
data = get_training_data(),
xlab = "Petal.Length",
ylab = "Petal.Width",
main = "Iris Dataset",
cex = 1.5, pch = 16, bty = "n")
if(!is.null(model())){
abline(model(), col = "blue", lwd = 2)
}
})
# closing reactive statement
})
# curly brace for server function
}
shinyApp(ui, server)
You were assigning the wrong data type to the output$plot1.
It expects something that was created by the function renderPlot(...) while you were giving it a result of reactive(...).
Restructure your code such that you immediately assign
output$plot1 <- renderPlot(...)
Since renderPlot opens a reactive environment, just as reactive does, you can just replace the function. But make sure that you remove the renderPlot calls from within the environment.
After changing that, you will run into some more errors you have in your code but I bet you can work it out from there.
Related
I want to create a clickable histogram in shiny but I don't know if it is possible.
Some months ago I saw a clickable volcano plot which gives you a table of what you click.
Source: https://2-bitbio.com/2017/12/clickable-volcano-plots-in-shiny.html
The closest post that I found about creating clickable histograms is this one Click to get coordinates from multiple histogram in shiny
However, I don't want to get the coordinates. I want the rownames of the dataframe.
Having this dataframe, can I get the rownames everytime I click a bar from the histogram?
mtcars <- mtcars %>%
select("hp")
mtcars <- as.matrix(mtcars)
One example (but not clickable) in shiny:
library(shiny)
library(ggplot2)
library(scales)
library(dplyr)
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("hist"),
)
)
)
mtcars <- mtcars %>%
select("hp")
mtcars <- as.matrix(mtcars)
server <- function(input, output) {
output$hist <- renderPlot({
pp <- qplot(mtcars, geom = "histogram", bins = 10, xlab="values",
ylab="Frequency", main="Histogram",
fill=I("red"), col=I("black"), alpha=I(0.4))
pp + scale_x_continuous(breaks=pretty(mtcars, n=10))
})
}
shinyApp(ui = ui, server = server)
Does anyone know how to do it?
Thanks very much in advance!
Regards
This is a great question, and what makes it challenging is that the qplot/ggplot charts are static images. The below app.r is an example of how I would do it. I'd love to see other approaches.
In essence:
Create a sequence of numbers that will be used both as the breaks in your histogram and as intervals in your dataframe. I based these on user inputs, but you could hardcode them.
Assign a "bin" value to each row in the dataframe based on the interval in which the value falls.
Record the x-coordinate from the user's click event and assign that a "bin" value based on the same set of intervals.
Subset your dataframe and retain only those records where the "bin" value of the data matches the "bin" value of the x-coordinate from the user's click event.
Otherwise, if you're willing to go the d3 route, you could explore something like this posted by R Views.
#Load libraries ----------------------------------------------------
library(shiny)
library(ggplot2)
library(scales)
library(dplyr)
# Prepare data -----------------------------------------------------
df <- mtcars
df <- cbind(model = rownames(df), data.frame(df, row.names = NULL)) # setting the rownames as the first column
dm <- df$hp %>% as.matrix()
# UI function ------------------------------------------------------
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
tags$h5("I added the below text output only to demonstrate shiny's way for tracking user interaction on static plots. You can click, double-click, or click & drag (i.e. brushing). These functions are AWESOME when exploring scatterplots."),
tags$h3("Chart click and brushing"),
verbatimTextOutput("info"),
tags$h5("Now I'm applying the below UI inputs to the `vec` and `breaks` arguments in `findInterval()` and `qplot()` respectively; I'm using `findInterval()` to bin the values in the dataframe AND to bin the x-value of the user's click event input on the chart. Then we can return the dataframe rows with the same bin values as the x-value of the click input."),
sliderInput("seq_from_to"
, label = h3("Sequence 'From' and 'To'")
, min = 0
, max = 500
, value = c(50, 350)
),
sliderInput("seq_by"
, label = h3("Sequence 'By'")
, min = 25
, max = 200
, value = 50
, step = 5)
),
mainPanel(
plotOutput("hist",
click = "plot_click",
dblclick = "plot_dblclick",
hover = "plot_hover",
brush = "plot_brush"),
dataTableOutput("table")
)
)
)
# Server function --------------------------------------------------
server <- function(input, output) {
# Render Histogram Plot
output$hist <- renderPlot({
# Using the same `qplot` function but inserting the user inputs to set the breaks values in the plot
pp <- qplot(dm
, geom = "histogram"
, breaks = seq(from = input$seq_from_to[1], to = input$seq_from_to[2], by = input$seq_by)
, xlab = "values"
, ylab = "Frequency"
, main = "Histogram"
, fill = I("red")
, col = I("black")
, alpha = I(0.4)
)
# Also using the user inputs to set the breaks values for the x-axis
pp + scale_x_continuous(breaks = seq(from = input$seq_from_to[1], to = input$seq_from_to[2], by = input$seq_by))
})
# This is purely explanatory to help show how shiny can read user interaction on qplot/ggplot objects
# It's taken from the Shiny docs here: https://shiny.rstudio.com/articles/plot-interaction.html
output$info <- renderText({
# Retain the x and y coords of the user click event data
xy_str <- function(e) {
if(is.null(e)) return("NULL\n")
paste0("x=", round(e$x, 1), " y=", round(e$y, 1), "\n")
}
# Retain the x and y range coords of click & drag (brush) data
xy_range_str <- function(e) {
if(is.null(e)) return("NULL\n")
paste0("xmin=", round(e$xmin, 1), " xmax=", round(e$xmax, 1),
" ymin=", round(e$ymin, 1), " ymax=", round(e$ymax, 1))
}
# Paste this together so we can read it in the UI function for demo purposes
paste0(
"click: ", xy_str(input$plot_click),
"dblclick: ", xy_str(input$plot_dblclick),
"hover: ", xy_str(input$plot_hover),
"brush: ", xy_range_str(input$plot_brush)
)
})
# Back to the story. Set a listener to trigger when one of the following is updated:
toListen <- reactive({list(
input$plot_click # user clicks on the plot
, input$seq_from_to # user updates the range slider
, input$seq_by # user updates the number input
)
})
# When one of those events are triggered, update the datatable output
observeEvent(toListen(), {
# Save the user click event data
click_data <- input$plot_click
print(click_data) # during your app preview, you can watch the R Console to see what click data is accessible
# Assign bin values to each row using the intervals that are set by the user input
df$bin <- findInterval(dm, vec = seq(from = input$seq_from_to[1], to = input$seq_from_to[2], by = input$seq_by))
# Similarly assign a bin value to the click event based on what interval the x values falls within
click_data$x_bin <- findInterval(click_data$x, vec = seq(from = input$seq_from_to[1], to = input$seq_from_to[2], by = input$seq_by))
# Lastly, subset the df to only those records within the same interval as the click event x-value
df_results <- subset(df, bin == click_data$x_bin)
# Select what values to view in the table
df_results <- df_results %>% select(model, hp)
# And push these back out to the UI
output$table <- renderDataTable(df_results,
options = list(
pageLength = 5
)
)
})
}
shinyApp(ui = ui, server = server)
Well, someone answered. Since I took the time to put it together, here is another potential solution.
library(shiny)
library(ggplot2)
library(scales)
library(dplyr)
library(DescTools) # added for Closest()
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("hist", click = 'plot_click'), # added plot_click
verbatimTextOutput("x_value"), # added queues for interactivity
verbatimTextOutput("selected_rows") # added table for bin values
)
)
)
# this can be a dataframe or matrix for qplot or ggplot
# (not sure if there was another reason you had this code?)
# mtcars <- mtcars %>%
# select("hp") # if you only want hp
# mtcars <- as.matrix(mtcars) # I suggest making row names a column
# to keep 2 columns
pp <- ggplot(mtcars) +
geom_histogram(aes(x = hp),
bins = 10,
fill = "red",
color = "black",
alpha = .4) +
labs(x = "values",
y = "Frequency",
title = "Histogram")
# extract data from plot to find where each value falls within the histogram bins
# I kept the pkg name, function in more than one library
bd <- ggplot_build(ggplot2::last_plot())$data[[1]]
# add the assigned bin number to the mtcars frame; used for filtering matches
mtcars$bins <- lapply(mtcars$hp,
function(y) {
which(bd$x == Closest(bd$x, y))
}) %>% unlist()
server <- function(input, output) {
output$hist <- renderPlot({
# moved the plot outside of server, so that global variables could be created
# pp <- qplot(mtcars[,"hp"], geom = "histogram", bins = 10, xlab="values",
# ylab = "Frequency", main = "Histogram",
# fill = I("red"), col = I("black"), alpha = I(0.4))
# scale_x_continuous(breaks=pretty(mtcars, n=10)) # can't use this
pp
})
# # Print the name of the x value # added all that's below with server()
output$x_value <- renderPrint({
if (is.null(input$plot_click$x)) return()
# find the closest bin center to show where the user clicked on the histogram
cBin <- which(bd$x == Closest(bd$x, input$plot_click$x))
paste0("You selected bin ", cBin) # print out selected value based on bin center
})
# Print the rows of the data frame which match the x value
output$selected_rows <- renderPrint({
if (is.null(input$plot_click$x)) return()
# find the closest bin center to show where the user clicked on the histogram
cBin <- which(bd$x == Closest(bd$x, input$plot_click$x))
mtcars %>% filter(bins == cBin)
# mtcars
})
}
shinyApp(ui = ui, server = server)
Just in case someone ends in this post looking a way to include brushedPoints... inspired on this post, I found a way to do it!
Code:
#Load libraries ----------------------------------------------------
library(shiny)
library(ggplot2)
library(scales)
library(dplyr)
# Prepare data -----------------------------------------------------
df <- mtcars
df <- cbind(model = rownames(df), data.frame(df, row.names = NULL)) # setting the rownames as the first column
breaks_data = pretty(mtcars$hp, n=10)
my_breaks = seq(min(breaks_data), to=max(breaks_data), by=30)
# UI function ------------------------------------------------------
ui <- fluidPage(
titlePanel("Histogram"),
sidebarLayout(
sidebarPanel(
actionButton("draw_plot", "Draw the plot")
),
mainPanel(
plotOutput("hist",
brush = brushOpts("plot_brush", resetOnNew = T, direction = "x")),
dataTableOutput("table"),
)
)
)
# Server function --------------------------------------------------
server <- function(input, output) {
observeEvent(input$plot_brush, {
info_plot <- brushedPoints(df, input$plot_brush)
output$table <- renderDataTable(info_plot)
})
# If the user didn't choose to see the plot, it won't appear.
output$hist <- renderPlot({
df %>% ggplot(aes(hp)) +
geom_histogram(alpha=I(0.4), col = I("black"), fill = I("red"), bins=10) +
labs(x = "values",
y = "Frequency",
title = "Histogram") +
scale_x_continuous(breaks = my_breaks)
})
}
shinyApp(ui = ui, server = server)
How to do a scatterplot with hover
library(shiny)
library(tidyverse)
ui <- fluidPage(
titlePanel("hover tooltips demo"),
mainPanel(
plotOutput("plot1", hover = hoverOpts(id = "plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info") # , style = "pointer-events: none")
)
)
server <- function(input, output) {
output$plot1 <- renderPlot({
mtcars %>%
ggplot(aes(mpg, hp)) +
geom_point()
})
output$hover_info <- renderUI({
hover <- input$plot_hover
point <- shiny::nearPoints(mtcars,
coordinfo = hover,
xvar = 'mpg',
yvar = 'hp',
threshold = 20,
maxpoints = 1,
addDist = TRUE)
if (nrow(point) == 0) return(NULL)
style <- paste0("position:absolute; z-index:100; background-color: #3c8dbc; color: #ffffff;",
"font-weight: normal; font-size: 11pt;",
"left:", hover$coords_css$x + 5, "px;",
"top:", hover$coords_css$y + 5, "px;")
wellPanel(
style = style,
p(HTML(paste0("Some info about car: <br/>MPG ", point$mpg, "<br/>HP ", point$hp)))
)
})
}
shinyApp(ui = ui, server = server)
I am trying to create an easy application with R shiny. However I could not get the desired output I want. I am neither experienced in shiny nor an expert of R. Here is the code:
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
checkboxGroupInput("plots", "draw plots:",
choices=list("histogram", "qq","both"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=seq(0:5), min=0, max=5),
numericInput("sd","standart deviation",value=seq(0:5),min=0,max=5),
numericInput("n", " number of observations ", value=seq(30,50))
),
mainPanel(
textOutput("text1"),
fluidRow(splitLayout(cellWidths = c("60%", "40%"),
plotOutput("graph1"), plotOutput("graph2")))
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distrubution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$graph1<-renderPlot({
if(identical(input$plots,"histogram")){
req(norm())
hist(norm())
}
})
output$graph2<- renderPlot({
if(identical(input$plots,"qq")) {
req(norm())
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
observe({
if(identical(input$plots,"both")) {
req(norm())
output$graph1<- renderPlot({
hist(norm())
})
output$graph2<- renderPlot({
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
})
}
})
}
shinyApp(ui = ui, server = server)
I want the plot layout change dynamically according to selection of checkboxGroupInput. When I click histogram or qq I want it to plot an unsplit frame, into only one plotting frame. Whereas when I click both I want the plots to be seen together in a split frame of two rows. When unclicked the layout must be reset to one frame again. I know I am not doing it right by splitting the layout in ui first. I saw something about renderUI function but could not understand how it works. Thanks in advance.
Also I got some error related to if statement:
Warning in if (!is.na(attribValue)) { :
the condition has length > 1 and only the first element will be used
Warning in charToRaw(enc2utf8(text)) :
argument should be a character vector of length 1
all but the first element will be ignored
Here is a start, you don't need the observer, you can just add an if statement to each renderPlot.
Update: The trick to getting the plots to update dynamically is to assign them into a list and then render the list of plots with renderUI, the only caveat to this is that I am unaware of a way to get these plots to render side-by-side at the moment, it probably has something to do with adding some div tags...
Update 2: To get the plots side by side we just need to wrap the plotOutput in column
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
checkboxGroupInput("plots", "draw plots:",
choices=list("histogram", "qq"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=1, min=0, max=5),
numericInput("sd","standart deviation",value=1,min=0,max=5),
numericInput("n", " number of observations ", value=30)
),
mainPanel(
textOutput("names"),
textOutput("text1"),
fluidRow(uiOutput("plot_list"))
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distribution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$histogram <- renderPlot({
req(norm())
if("histogram" %in% input$plots){
hist(norm())
}
})
output$qq <- renderPlot({
req(norm())
if("qq" %in% input$plots){
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
output$plot_list <- renderUI({
plot_output_list <- lapply(input$plots,
function(plotname) {
column(width=5, plotOutput(plotname)) ##wrap the plotOutput in column to render side-by-side
})
# Convert the list to a tagList - this is necessary for the list of items
# to display properly.
do.call(tagList, plot_output_list)
})
}
shinyApp(ui = ui, server = server)
You can have a single plotOutput and use mfrow to split it into two panels, like this:
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
radioButtons("plots", "draw plots:",
choices=list("histogram", "qq","both"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=seq(0:5), min=0, max=5),
numericInput("sd","standart deviation",value=seq(0:5),min=0,max=5),
numericInput("n", " number of observations ", value=seq(30,50))
),
mainPanel(
textOutput("text1"),
plotOutput("graph")
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distrubution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$graph = renderPlot({
if(input$plots == "both") {
par(mfrow = c(1, 2))
}
if(is.element(input$plots, c("histogram", "both"))) {
req(norm())
hist(norm())
}
if(is.element(input$plots, c("qq", "both"))) {
req(norm())
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
}
shinyApp(ui = ui, server = server)
If you want two rows instead of two columns, just change par(mfrow = c(1, 2)) to par(mfrow = c(2, 1)).
(I'm still getting the error on if too, but it doesn't seem to affect the functioning of the app, at least as far as the graphs are concerned. I'm not sure where it's coming from.)
I have a shiny app which generates 2 plots and one table. As you will see I want to select which one of them will be displayed every time based on the radiobuttons() input. Until now I get an error object of type 'closure' is not subsettable Which object exactly is of type closure? Note that the first is a ggplot object the second is a plotly object and the third a datatable.
# ui.R
library(shiny)
library(plotly)
pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
uiOutput("filter_degree")
),
mainPanel(
uiOutput('plot')
)
)
#server.r
function(input, output, session) {
output$filter_degree<-renderUI({
radioButtons("rd","Select Option",choices = c("Mileage","Regression",'Table'),
selected = "Mileage")
})
output$plot <- renderUI({
if(input$rd=="Mileage"){
output$plot1<-renderUI({
# Boxplots of mpg by number of gears
# observations (points) are overlayed and jittered
qplot(gear, mpg, data=mtcars, geom=c("boxplot", "jitter"),
fill=gear, main="Mileage by Gear Number",
xlab="", ylab="Miles per Gallon")
})
}
else if(input$rd=="Regression"){
output$plot2<-renderUI({
x <- c(1:100)
random_y <- rnorm(100, mean = 0)
data <- data.frame(x, random_y)
p <- plot_ly(data, x = ~x, y = ~random_y, type = 'scatter', mode = 'lines')
})
}
else if(input$rd=="Table"){
output$tbl = DT::renderDataTable(datatable(
iris, options = list(lengthChange = FALSE,scrollY = T, scroller = TRUE, scrollX = T),selection = list(target="cell",mode="single"),rownames = F)
)
}
})
}
You need to provide the plot/table output as part of the if/then sequence (plotOutput("plot1"), etc.). Otherwise, it has nothing to render. Also, there appears to be an error in the ploty call, but I haven't fixed it for you.
library(shiny)
library(DT)
library(plotly)
ui <- pageWithSidebar(
headerPanel('Iris k-means clustering'),
sidebarPanel(
uiOutput("filter_degree")
),
mainPanel(
uiOutput('plot')
)
)
#server.r
server <- function(input, output, session) {
output$filter_degree<-renderUI({
radioButtons("rd","Select Option",choices = c("Mileage","Regression",'Table'),
selected = "Mileage")
})
output$plot <- renderUI({
if(input$rd=="Mileage"){
output$plot1<-renderPlot({
# Boxplots of mpg by number of gears
# observations (points) are overlayed and jittered
qplot(gear, mpg, data=mtcars, geom=c("boxplot", "jitter"),
fill=gear, main="Mileage by Gear Number",
xlab="", ylab="Miles per Gallon")
})
plotOutput("plot1")
}
else if(input$rd=="Regression"){
output$plot2<-renderUI({
x <- c(1:100)
random_y <- rnorm(100, mean = 0)
data <- data.frame(x, random_y)
p <- plot_ly(data, x = ~x, y = ~random_y, type = 'scatter', mode = 'lines')
})
plotlyOutput("plot2")
}
else if(input$rd=="Table"){
output$tbl = DT::renderDataTable(datatable(
iris, options = list(lengthChange = FALSE,scrollY = T, scroller = TRUE, scrollX = T),selection = list(target="cell",mode="single"),rownames = F)
)
dataTableOutput("tbl")
}
})
}
shinyApp(ui = ui, server = server)
I've been thinking if there's an answer to the question.
So i have this code in server.R
desc <- reactive({
for (i in 1:input$txt1){
print(paste("Cluster ke", i))
clust <- ensemble()
newdata <- clust[which(clust$Cluster==i), 1]
print(paste(newdata))
barm <- vector("numeric")
x <- ncol(clust)-2
for (j in 2:x){
datdesc <- clust[which(clust$Cluster==i), j]
m <- mean(datdesc)
colnam <- colnames(clust[j])
print(paste("Rata-rata produktivitas", colnam,":", m))
for(k in j-1){
barm[k] <- m
}
}
print(paste(barm))
barplot(barm)
}
})
output$desc <- renderPrint({
desc()
})
And this in the ui
conditionalPanel(condition="input.choice==3", verbatimTextOutput("desc"))
So far, i can get all the output i wanted, the descriptive text and the bar plot. But, the bar plot is appears at the R console instead on the browser.
Is there any way to make the text and barplot show up at the same page?
Can i use other function of renderPrint or verbatimTextOutput that possibly can do that?
Or any other ways?
I've been thinking some solution to this, like dividing the desc() so it has two outputs, text and barplot. But if there's a way to make it in one go, I'm very much want to learn that way.
Sure, it's common to have many different output types. Please see the Shiny gallery for more examples.
Based on the code you provided and a template:
UI.R
bootstrapPage(
selectInput(
"choice", "txt1 - descriptive text?",
c(my_text = "my_text",
your_text = "your_text")),
selectInput(inputId = "n_breaks",
label = "Number of bins in histogram (approximate):",
choices = c(10, 20, 35, 50),
selected = 20),
checkboxInput(inputId = "individual_obs",
label = strong("Show individual observations"),
value = FALSE),
checkboxInput(inputId = "density",
label = strong("Show density estimate"),
value = FALSE),
plotOutput(outputId = "main_plot", height = "300px"),
conditionalPanel(condition="input.choice=='my_text'", verbatimTextOutput("desc"))
)
Server.R
function(input, output) {
desc <- reactive({
"some text goes here, I guess!"
})
output$desc <- renderPrint({
desc()
})
output$main_plot <- renderPlot({
hist(faithful$eruptions,
probability = TRUE,
breaks = as.numeric(input$n_breaks),
xlab = "Pandjie Soerja",
main = "Pandjie Soerja")
if (input$individual_obs) {
rug(faithful$eruptions)
}
if (input$density) {
dens <- density(faithful$eruptions,
adjust = input$bw_adjust)
lines(dens, col = "blue")
}
})
}
Edited: I removed to the call to get a dataset from data.world and instead fed in the mtcars dataset which produces the same error of contrasts can only be applied to factors of 2 or more
I am learning shiny and wanted to create a plot that gives the linear regression line for both a) the whole plot and b) linear regression line for brushed points on the plot. I would even settle for just showing the summary stats for the regression of the brushed points.
The code below
plots the user inputs for x and y
allows the user to brush points
creates a reactive datasubset of brushed points
shows summary of the regression for all points
shows data table of the reactive datasubset of brushed points when a brush is applied
breaks down when asked to perform a regression on those brushed points for reasons I do not understand...
code:
library(shiny)
library(ggplot2)
library(data.world)
library(dplyr)
library(tidyverse)
library(DT)
#show data from data.world
gcdata_ds <- "https://data.world/llawsonwork/gcdata"
#gcdatafile <- data.world::query(
#qry_sql("SELECT * FROM gcdataclean"),
#dataset =gcdata_ds
#)
#datafile <- gcdatafile
#so that you will not need data.world
datafile <-mtcars
# Define UI for application that draws a histogram
ui <- fluidPage(
#Application Layout
sidebarLayout(
#Inputs
sidebarPanel(
#select variable for y-axis
selectInput(inputId = "ya",
label = "Y-axis",
choices = colnames(datafile),
selected = "life_expec"
),
#Select Variable for x axis
selectInput(inputId = "xa",
label = "X-axis",
choices = colnames(datafile),
selected = "life_expec"
)
),
#output
mainPanel(
plotOutput(outputId = "guilfordplot", brush = "plot_brush"),
htmlOutput(outputId = "summary"), # summary of lin regress all points
dataTableOutput(outputId = "brushedtracts"), # data table to make sure brushed points are updating correctly
textOutput(outputId = "brushedreg") # NOT Working summary of lin reg brushed points
)
)
)
#define server function
server <- function(input, output){
#this was useful in creating the regression model as X was always column 1 and Y was always column in this dataframe
datasubset <- reactive({
req(input$xa)
req(input$ya)
data.frame(X = datafile[input$xa], Y = datafile[input$ya])
})
#create datasubset of the brushed points
brushedsubset <- reactive({
req(input$xa)
req(input$ya)
req(input$plot_brush)
brushedPoints(datafile, brush = input$plot_brush) %>%
select(input$xa, input$ya)
})
#Create plot
output$guilfordplot <- renderPlot({
ggplot(data = datafile, aes_string(x = input$xa, y = input$ya)) +
geom_point() + geom_smooth(method = "lm")
})
#create summary file
output$summary <- renderUI({
model = lm(datasubset()[,2] ~ datasubset()[,1], data = datasubset())
r2 = format(summary(model)$r.squared, digits = 3)
txt = paste("The equation of the line is :\nY = ",
round(coefficients(model)[1],0), " + ",
round(coefficients(model)[2], 5), "X")
# str_3 <- format(coef(m)[1], digits = 3)
str_1 <- txt
str_2 <- paste("The R^2 value is equal to ", r2)
HTML(paste(str_1, str_2, sep = '<br/>'))
})
# create data table
output$brushedtracts <- DT::renderDataTable({
select(brushedsubset(), input$xa, input$ya)
})
# create brushed summary stats
output$brushedreg <- renderText({
modelbrush = lm(brushedsubset()[,2] ~ brushedsubset()[,1], data = brushedsubset())
br2 = format(summary(modelbrush)$r.squared, digits = 3)
btxt = paste("The equation of the line is :\nY = ",
round(coefficients(modelbrush)[1],0), " + ",
round(coefficients(modelbrush)[2], 5), "X")
paste(btxt, ' and the rsquared is: ', br2 )
})
}
# Run the application
shinyApp(ui = ui, server = server)
So the code above works for the summary regression of all points for a given x and y input.
But this code does not work for giving me the linear regression of the brushed points and I cannot figure out why because it is the nearly identical for the code for the linear regression of all points.
Any help would be appreciated and it there is a tidyer way of doing the linear regression and summary stats please let me know.