I'm trying create a plot where I'm able to zoom in on a range and the y-axis rescales. Similar to Rescaling of y axis on an interactive plot depending on zoom except that I would like it to happen on double click.
library(shiny)
library(tidyverse)
ui <- fluidPage(
sidebarPanel(
actionButton('getdata', 'Get Data')
),
mainPanel(
plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick')
)
)
server <- function(input, output, session) {
dat <- eventReactive(input$getdata, {
tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11))
})
dat2 <- reactive(dat())
observeEvent(input$dclick, {
brush <- input$brush
maxy <- brush$xmax
miny <- brush$xmin
if (is.null(miny)){
dat2(dat())
}else{
dat2(dat() %>% filter(BusDate > miny & BusDate < maxy))
}
}, ignoreInit = TRUE)
output$plot <- renderPlot({
ggplot(dat2(), aes(x = BusDate, y = Val)) + geom_line()
})
}
shinyApp(ui, server)
I keep getting an error that doesn't allow me to update dat2 within observe event.
Error in dat2: unused argument (dat() %>% filter(BusDate > miny & BusDate < maxy))
How do I update dat2 within observeEvent? I understand that its easier to update reactiveValues instead but I would like to know how it works specifically with reactiveVal
Try this:
library(shiny)
library(tidyverse)
ui <- fluidPage(
sidebarPanel(
actionButton('getdata', 'Get Data')
),
mainPanel(
plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick')
)
)
server <- function(input, output, session) {
dat <- eventReactive(input$getdata, {
tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11))
})
dat2 <- reactiveVal()
observeEvent(input$dclick, {
brush <- input$brush
maxy <- brush$xmax
miny <- brush$xmin
if (is.null(miny)){
dat2(dat())
}else{
dat2(dat() %>% filter(BusDate > miny & BusDate < maxy))
}
}, ignoreInit = TRUE)
output$plot <- renderPlot({
df <- if(is.null(dat2())) dat() else dat2()
ggplot(df, aes(x = BusDate, y = Val)) + geom_line()
})
}
shinyApp(ui, server)
You are confusing reactive with reactiveVal. You can only update the value of reactive within its definition. Update with obj(xxx) is for reactiveVal.
Related
I have a larger application where i need to identify data clusters.
For this I would like to create a pair plot and use the brush option to mark some points. These marked points are later used in another part of the program.
The problem is that i can not specify the xvar and yvar parameters for the pair plot.
At the moment i have no idea how to solve this.
Is there someone around who had the same problem?
I tried to create a simple application that demonstrates the problem.
Finally i need the IMG_Selected_Tiles variable to mark specific parts of a source image...
Thanks for any help
Jan
IMG_SelectedTiles <- reactiveValues ()
IMG_Statistics <- reactiveValues ()
library ("ggplot2")
shinyApp(
ui = basicPage(
fluidRow(
column(width = 4,
plotOutput("plot", height=300,
click = "plot_click", # Equiv, to click=clickOpts(id="plot_click")
hover = hoverOpts(id = "plot_hover", delayType = "throttle"),
brush = brushOpts(id = "plot_brush")
),
h4("Clicked points"),
tableOutput("plot_clickedpoints"),
h4("Brushed points"),
tableOutput("plot_brushedpoints")
),
column(width = 4,
verbatimTextOutput("plot_clickinfo"),
verbatimTextOutput("plot_hoverinfo")
),
column(width = 4,
wellPanel(actionButton("newplot", "New plot")),
verbatimTextOutput("plot_brushinfo"),
verbatimTextOutput("text_IMG_selected_tiles")
)
)
),
server = function(input, output, session) {
IMG_Statistics$data <- reactive({
input$newplot
iris
})
output$plot <- renderPlot({
d <- IMG_Statistics$data ()
ggpairs (d)
#plot(d$speed, d$dist)
})
output$plot_clickinfo <- renderPrint({
cat("Click:\n")
str(input$plot_click)
})
output$plot_hoverinfo <- renderPrint({
cat("Hover (throttled):\n")
str(input$plot_hover)
})
output$plot_brushinfo <- renderPrint({
cat("Brush (debounced):\n")
str(input$plot_brush)
})
output$plot_clickedpoints <- renderTable({
# For base graphics, we need to specify columns, though for ggplot2,
# it's usually not necessary.
res <- nearPoints(IMG_Statistics$data(),
input$plot_click,
"speed",
"dist")
if (nrow(res) == 0) return()
res
})
output$plot_brushedpoints <- renderTable({
res <- brushedPoints(IMG_Statistics$data(), input$plot_brush, allRows = TRUE)
if (nrow (res) == 0) return()
#just as an example data are taken from another data structure
IMG_SelectedTiles <- cbind(IMG_Statistics$data [res_selected_, 1],
IMG_Statistics$data [res_selected_, 2],
IMG_Statistics$data [res_selected_, 3])
})
output$text_IMG_selected_Tiles <-renderTable ({
cat ("Selected data:\n")
str (IMG_Selected_Tiles())
})
}
)
Maybe with the help of plotly?
library(plotly)
library(GGally)
library(shiny)
ui <- fluidPage(
plotlyOutput("myPlot"),
)
server <- function(input, output, session){
output$myPlot = renderPlotly({
highlight_key(iris) %>%
GGally::ggpairs(aes(color = Species), columns = 1:4) %>%
ggplotly() %>%
highlight("plotly_selected") %>%
layout(dragmode = "select") %>%
event_register(event = "plotly_brushed") %>%
event_register(event = "plotly_selected")
})
observeEvent(event_data("plotly_brushed"), {
cat("Selected box:\n")
print(event_data("plotly_brushed"))
# alternative method
#xmin <- event_data("plotly_brushed")$x[1]
#xmax <- event_data("plotly_brushed")$x[2]
#ymin <- event_data("plotly_brushed")$y[1]
#ymax <- event_data("plotly_brushed")$y[2]
})
observeEvent(event_data("plotly_selected"), {
cat("Selected points:\n")
print(event_data("plotly_selected"))
})
}
shinyApp(ui, server)
Thanks for your help, Stéphane!
I finally made a solution for the problem, using your approach in a very similar way.
I think, that this is a little tricky problem. Thus, I prepared some sample code. It is not the most elegant sample, but it may help some others facing a similar problem...
Jan
library ("plotly")
IMG_SelectedTiles <- reactiveValues ()
IMG_Statistics <- reactiveValues ()
IMG_selected_keys <- reactiveValues ()
IMG_selected_points <- reactiveValues ()
ui <- fluidPage(
wellPanel(actionButton("newplot", "New plot")),
plotlyOutput("myPlot"),
h4 ("Selected points"),
tableOutput("selected_points"),
h4 ("Selected keys"),
tableOutput("selected_keys"),
h4 ("Selected data"),
tableOutput("selected_data")
)
server <- function(input, output, session){
# get arbitrary data into my reactive variable
IMG_Statistics$data <- reactive({
input$newplot
iris
})
output$myPlot = renderPlotly({
#height = "1500px"
#width = "1500px",
highlight_key(IMG_Statistics$data() ) %>%
GGally::ggpairs () %>%#(aes(color = "black"), columns = 1:4) %>%
ggplotly() %>%
highlight("plotly_selected") %>%
layout(dragmode = "select", autosize = FALSE, height = 1500, width = 1500) %>%
# event_register(event = "plotly_brushed") %>%
event_register(event = "plotly_selected")
})
observeEvent(event_data("plotly_brushed"), {
# cat("Selected brush:\n")
# print (str (event_data("plotly_brushed")))
# alternative method
#xmin <- event_data("plotly_brushed")$x[1]
#xmax <- event_data("plotly_brushed")$x[2]
#ymin <- event_data("plotly_brushed")$y[1]
#ymax <- event_data("plotly_brushed")$y[2]
})
observeEvent(event_data("plotly_selected"), {
cat("Data:\n")
print (str (IMG_Statistics$data))
IMG_selected_keys$data <- event_data("plotly_selected")$key
cat("Selected keys:\n")
print ( IMG_selected_keys$data)
IMG_selected_points$data <- event_data("plotly_selected")$pointNumber
cat("Selected point numbers:\n")
print (IMG_selected_points$data)
IMG_SelectedTiles$data <- IMG_Statistics$data () [as.numeric (event_data ("plotly_selected")$key), ]
cat("Selected tiles:\n")
print (IMG_SelectedTiles$data)
})
output$selected_keys <- renderPrint ({IMG_selected_keys$data })
output$selected_points <- renderPrint ({IMG_selected_points$data})
output$selected_data <- renderTable({
IMG_SelectedTiles$data
})
}
shinyApp(ui, server)
I am new to R and Shiny package. I have a csv file with 4 col and 600 rows and I am trying to plot some graphs using ggplot2.
My ui and server codes are like:
dt<-read.csv('file.csv')
server <- function(input, output) {
output$aPlot <- renderPlot({
ggplot(data = dt, aes(x = Col1, y = Col2, group = 'Col3', color = 'Col4')) + geom_point()
})
}
ui <- fluidPage(sidebarLayout(
sidebarPanel(
sliderInput("Obs", "Log FC", min = 1, max = 600, value = 100)
),
mainPanel(plotOutput("aPlot")) ))
Here, I can get the ggplot output but I don't know how to use this slider input to control the number of rows to be read i.e., I want this "Obs" input to define the size of Col1 to be used in the graph.
Try something like this, example here is with mtcars dataset:
library(shiny)
library(ggplot2)
dt <- mtcars[,1:4]
ui <- fluidPage(
sidebarPanel(
sliderInput("Obs", "Log FC", min = 1, max = nrow(dt), value = nrow(dt)-10)
),
mainPanel(plotOutput("aPlot"))
)
server <- function(input, output) {
mydata <- reactive({
dt[1:as.numeric(input$Obs),]
})
output$aPlot <- renderPlot({
test <- mydata()
ggplot(data = test, aes(x = test[,1], y = test[,2], group = names(test)[3], color = names(test)[4])) + geom_point()
})
}
shinyApp(ui = ui, server = server)
Change your server to:
server <- function(input, output) {
observe({
dt_plot <- dt[1:input$Obs,]
output$aPlot <- renderPlot({
ggplot(data = dt_plot, aes(x = Col1, y = Col2, group = 'Col3', color = 'Col4')) + geom_point()
})
})
}
I would really appreciate some help with the following code:
library(shiny)
library(rhandsontable)
library(tidyr)
dataa <- as.data.frame(cbind(rnorm(100, sd=2), rchisq(100, df = 0, ncp = 2.), rnorm(100)))
ldataa <- gather(dataa, key="variable", value = "value")
thresholds <- as.data.frame(cbind(1,1,1))
ui <- fluidPage(fluidRow(
plotOutput(outputId = "plot", click="plot_click")),
fluidRow(rHandsontableOutput("hot"))
)
server <- function(input, output) {
values <- reactiveValues(
df=thresholds
)
observeEvent(input$plot_click, {
values$trsh <- input$plot_click$x
})
observeEvent(input$hot_select, {
values$trsh <- 1
})
output$hot = renderRHandsontable({
rhandsontable(values$df, readOnly = F, selectCallback = TRUE)
})
output$plot <- renderPlot({
if (!is.null(input$hot_select)) {
x_val = colnames(dataa)[input$hot_select$select$c]
dens.plot <- ggplot(ldataa) +
geom_density(data=subset(ldataa,variable==x_val), aes(x=value), adjust=0.8) +
geom_rug(data=subset(ldataa,variable==x_val), aes(x=value)) +
geom_vline(xintercept = 1, linetype="longdash", alpha=0.3) +
geom_vline(xintercept = values$trsh)
dens.plot
}
})
}
shinyApp(ui = ui, server = server)
I have a plot and a handsontable object in the app.
Clicking on whichever cell loads a corresponding plot, with a threshold value. Clicking the plot changes the position of one of the vertical lines.
I would like to get the x value from clicking the plot into the corresponding cell, and I would like to be able to set the position of the vertical line by typing in a value in the cell too.
I'm currently a bit stuck with how I should feed back values into a reactiveValue dataframe.
Many thanks in advance.
This works as I imagined:
(The trick was to fill right columns of "df" with input$plot_click$x by indexing them with values$df[,input$hot_select$select$c].)
library(shiny)
library(rhandsontable)
library(tidyr)
dataa <- as.data.frame(cbind(rnorm(100, sd=2), rchisq(100, df = 0, ncp = 2.), rnorm(100)))
ldataa <- gather(dataa, key="variable", value = "value")
thresholds <- as.data.frame(cbind(1,1,1))
ui <- fluidPage(fluidRow(
plotOutput(outputId = "plot", click="plot_click")),
fluidRow(rHandsontableOutput("hot"))
)
server <- function(input, output) {
values <- reactiveValues(
df=thresholds
)
observeEvent(input$plot_click, {
values$df[,input$hot_select$select$c] <- input$plot_click$x
})
output$hot = renderRHandsontable({
rhandsontable(values$df, readOnly = F, selectCallback = TRUE)
})
output$plot <- renderPlot({
if (!is.null(input$hot_select)) {
x_val = colnames(dataa)[input$hot_select$select$c]
dens.plot <- ggplot(ldataa) +
geom_density(data=subset(ldataa,variable==x_val), aes(x=value), adjust=0.8) +
geom_rug(data=subset(ldataa,variable==x_val), aes(x=value)) +
geom_vline(xintercept = 1, linetype="longdash", alpha=0.3) +
geom_vline(xintercept = values$df[,input$hot_select$select$c])
dens.plot
}
})
}
shinyApp(ui = ui, server = server)
Update your reactiveValue dataframe from inside of an observeEvent, where you are watching for whichever event is useful, i.e. a click or something.
observeEvent(input$someInput{
values$df <- SOMECODE})
When I click one point in the chart, that point is highlighted as red.
But soon it goes back to black.
Is there any way to hold the selection?
library(shiny)
library(ggplot2)
server <- function(input, session, output) {
mtcars$cyl = as.character(mtcars$cyl)
D = reactive({
nearPoints(mtcars, input$click_1,allRows = TRUE)
})
output$plot_1 = renderPlot({
set.seed(123)
ggplot(D(),aes(x=cyl,y=mpg)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(aes(color=selected_),width=0.02,size=4)+
scale_color_manual(values = c("black","red"),guide=FALSE)
})
output$info = renderPrint({
D()
})
}
ui <- fluidPage(
plotOutput("plot_1",click = clickOpts("click_1")),
verbatimTextOutput("info")
)
shinyApp(ui = ui, server = server)
Okay, my approach is slightly different to Valter's: selected points become red, whilst you can deselect them and they turn back to black.
The key to achieve this effect (or even Valter's answer with 1 selected point) is to use reactiveValues to keep track of the selected points.
library(shiny)
library(ggplot2)
server <- function(input, session, output) {
mtcars$cyl = as.character(mtcars$cyl)
vals <- reactiveValues(clicked = numeric())
observeEvent(input$click_1, {
# Selected point/points
slt <- which(nearPoints(mtcars, input$click_1,allRows = TRUE)$selected)
# If there are nearby points selected:
# add point if it wasn't clicked
# remove point if it was clicked earlier
# Else do nothing
if(length(slt) > 0){
remove <- slt %in% vals$clicked
vals$clicked <- vals$clicked[!vals$clicked %in% slt[remove]]
vals$clicked <- c(vals$clicked, slt[!remove])
}
})
D = reactive({
# If row is selected return "Yes", else return "No"
selected <- ifelse(1:nrow(mtcars) %in% vals$clicked, "Yes", "No")
cbind(mtcars, selected)
})
output$plot_1 = renderPlot({
set.seed(123)
ggplot(D(),aes(x=cyl,y=mpg)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(aes(color=selected),width=0.02,size=4)+
scale_color_manual(values = c("black","red"),guide=FALSE)
})
output$info = renderPrint({
D()
})
}
ui <- fluidPage(
plotOutput("plot_1",click = clickOpts("click_1")),
verbatimTextOutput("info")
)
shinyApp(ui = ui, server = server)
I am not sure what is the problem but this is the first workaround I have come up to:
library(shiny)
library(ggplot2)
server <- function(input, session, output) {
mtcars$cyl = as.character(mtcars$cyl)
df <- reactiveValues(dfClikced = mtcars)
observe({
if (!is.null(input$click_1)) {
df$dfClikced <- nearPoints(mtcars, input$click_1, allRows = TRUE)
}})
output$plot_1 = renderPlot({
set.seed(123)
if (names(df$dfClikced)[NCOL(df$dfClikced)]== "selected_") {
ggplot(df$dfClikced,aes(x=cyl,y=mpg)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(aes(color=selected_),width=0.02,size=4)+
scale_color_manual(values = c("black","red"),guide=FALSE)
} else {
ggplot(df$dfClikced,aes(x=cyl,y=mpg)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(width=0.02,size=4)+
scale_color_manual(values = c("black","red"),guide=FALSE)
}
})
output$info = renderPrint({
df$dfClikced
})
}
ui <- fluidPage(
plotOutput("plot_1",click = clickOpts("click_1")),
verbatimTextOutput("info")
)
shinyApp(ui = ui, server = server)
let me know...
Could anyone can tell me why I get an error when I change a dataset in first selectInput widget? When I change a dataset from diamonds to mtcars I get an error Could not find 'carat' in input$bins and in the plot just for one second and after that everything works fine. Why it happened?
library(shiny)
library(ggplot2)
data(diamonds)
data(mtcars)
ui <- fluidPage(
column(3,
selectInput("data", "", choices = c('mtcars', 'diamonds')),
uiOutput('server_cols'),
uiOutput('server_bins')
),
column(9,
plotOutput("plot")
)
)
server <- function(input, output) {
data <- reactive({
switch(input$data,
diamonds = diamonds,
mtcars = mtcars)
})
output$server_cols <- renderUI({
data <- data()
nam <- colnames(data)
selectInput('cols', "Choose numeric columns:", choices = nam[sapply(data, function(x) is.numeric(x))])
})
output$server_bins <- renderUI({
if (!is.null(input$cols)) {
df <- data()
x <- eval(input$cols)
max_value <- max(df[,x])
sliderInput('bins','Choose number of bins:', min = 0.1,
max = max_value,
value = max_value/2)
}
})
output$plot <- renderPlot({
if (!is.null(input$cols) & !is.null(input$bins)) {
basicData <- data()
var <- eval(input$cols)
ggplot(basicData, aes_string(var)) +
geom_histogram(binwidth = input$bins, color = 'white', fill = 'red')
}
})
}
shinyApp(ui, server)
Your respective output objects respond to any changes of your input variables. Thus, when you change your dataset via input$data, the plot rebuilds itself, although input$cols did not yet adjust. Actually, try inserting some print("a") inside the output$plot to see that it is called up to three times if you change input$data.
The fix is to rethink your reaction logic and let your elements respond only to specific changes, to get some kind of response "thread".
For example, input$data should only trigger output$server_cols. And output$server_bins should only be triggered by input$cols (because this already implies that input$data changed earlier). Ultimately, output$plot just has to listen to changes of input$bins (because changes in input$cols and input$data always result in changes of input$bins since it is at the end of the thread).
Here is my suggestion using isolate.
library(shiny)
library(ggplot2)
data(diamonds)
data(mtcars)
ui <- fluidPage(
column(3,
selectInput("data", "", choices = c('mtcars', 'diamonds')),
uiOutput('server_cols'),
uiOutput('server_bins')
),
column(9,
plotOutput("plot")
)
)
server <- function(input, output) {
data <- reactive({
switch(input$data, diamonds = diamonds, mtcars = mtcars)
})
output$server_cols <- renderUI({
data <- data()
nam <- colnames(data)
selectInput('cols', "Choose numeric columns:", choices = nam[sapply(data, function(x) is.numeric(x))])
})
output$server_bins <- renderUI({
if (!is.null(input$cols)) {
df <- isolate(data())
x <- eval(input$cols)
max_value <- max(df[,x])
sliderInput('bins','Choose number of bins:', min = 0.1, max = max_value, value = max_value/2)
}
})
output$plot <- renderPlot({
if (!is.null(isolate(input$cols)) & !is.null(input$bins)) {
basicData <- isolate(data())
var <- eval(isolate(input$cols))
ggplot(basicData, aes_string(var)) +
geom_histogram(binwidth = input$bins, color = 'white', fill = 'red')
}
})
}
shinyApp(ui, server)
You might also want to look into updateSelectInput and updateSliderInput if you want to alter Input Elements depending on other input.