Is there a way to preselect points in ggiraph (R shiny)? - r

I would like to preselect some points in a ggiraph::renderggiraph() output.
I can make the following shiny app which allows me to select points and then use those selected points elsewhere like so:
dat <- data.table(x = 1:6, y = 1:6 %% 3, id = 1:6, status = rep(c('on','off'),3))
ui <- fluidPage( ggiraphOutput("plot"),
verbatimTextOutput("choices"))
server <- function(input, output, session){
output$plot <- renderggiraph({
p <- ggplot(dat ) +
geom_point_interactive(aes(x = x, y = y, data_id = id), size = 5) +
scale_color_manual(limits = c('on','off'),values = c('red','black'))
ggiraph(code = print(p),
hover_css = "fill:red;cursor:pointer;",
selection_type = "multiple",
selected_css = "fill:red;")
})
output$choices <- renderPrint({
input$plot_selected
})
}
shinyApp(ui = ui, server = server)
But sometimes I want to have certain points selected before I initialize the app.
For example, if the points 1, 3, and 5 are already "on" orginally, I would like the user to be able to turn them "off".
So my question is, is it possible to achieve something like this?

Yes, by using session$sendCustomMessage in session$onFlushed:
library(shiny)
library(ggiraph)
library(data.table)
library(magrittr)
dat <- data.table(x = 1:6, y = 1:6 %% 3, id = 1:6, status = rep(c('on','off'),3))
ui <- fluidPage( fluidRow(
column(width = 7,
ggiraphOutput("ggobj") ),
column(width = 5, verbatimTextOutput("choices"))
) )
server <- function(input, output, session){
output$ggobj <- renderggiraph({
p <- ggplot(dat ) +
geom_point_interactive(aes(x = x, y = y, data_id = id), size = 5) +
scale_color_manual(limits = c('on','off'),values = c('red','black'))
ggiraph(code = print(p),
hover_css = "fill:red;cursor:pointer;",
selection_type = "multiple",
selected_css = "fill:red;")
})
session$onFlushed(function(){
session$sendCustomMessage(type = 'ggobj_set', message = 1:3)
})
output$choices <- renderPrint({
input$ggobj_selected
})
}
shinyApp(ui = ui, server = server)

Related

R Shiny recoloring of points

I would like click-select points and group them based on color.
I can save selected points with color information into a new data frame and plot it, however I would like to keep track and see what was already selected on the interactive plot.
How can I show/label already selected points or make it permanent after "Add selection"?
library(shiny)
library(tidyverse)
library(DT)
library(colourpicker)
ui = fluidPage(
colourInput("col", "Select colour", "purple"),
actionButton("addToDT", "Add selection", icon = icon("plus")), hr(),
plotOutput("plot", click = "plot_click", dblclick = "plot_reset"),
DT::dataTableOutput('plot_DT'), hr(),
textOutput("clickcoord"),
DT::dataTableOutput('final_DT'),
plotOutput("plotSelected")
)
server = function(input, output, session) {
selectedPoint = reactiveVal(rep(FALSE, nrow(mtcars)))
output$clickcoord <- renderPrint({
print(input$plot_click)
})
observeEvent(input$plot_click, {
clicked = nearPoints(mtcars, input$plot_click, allRows = TRUE)$selected_
selectedPoint(clicked | selectedPoint())
})
observeEvent(input$plot_reset, {
selectedPoint(rep(FALSE, nrow(mtcars)))
})
output$plot_DT = DT::renderDataTable({
mtcars$sel = selectedPoint()
mtcars = dplyr::filter(mtcars, sel == TRUE) %>% mutate(group_color = input$col)
})
final_DT = reactiveValues()
final_DT$df = data.frame()
FinalData = eventReactive(input$addToDT, {
mtcars$sel = selectedPoint()
mtcars = dplyr::filter(mtcars, sel == TRUE) %>% mutate(group_color = input$col)
final_DT$df = bind_rows(final_DT$df, mtcars)
})
output$final_DT = renderDataTable({FinalData()})
output$plot = renderPlot({
mtcars$sel = selectedPoint()
ggplot(mtcars, aes(wt, mpg, color = mtcars$sel, fill=mpg)) +
geom_point(shape = 21, size = 6, stroke = 2) +
scale_color_manual(values = c("#ffffff00", input$col)) +
scale_fill_viridis_c() +
theme_bw()
})
output$plotSelected = renderPlot({
sel_df = FinalData()
ggplot(sel_df, aes(wt, mpg, fill = group_color, colour = group_color)) +
geom_point(shape = 21, size = 6, stroke = 2) +
scale_color_manual(values = unique(sel_df$group_color)) +
scale_fill_manual(values = unique(sel_df$group_color)) +
theme_bw()
})
observeEvent(input$addToDT, {
selectedPoint(rep(FALSE, nrow(mtcars)))
})
}
shinyApp(ui, server)
I think this is the "crux" of what your are looking for. I used a very similar example that I found in the help for entitled:
A demonstration of clicking, hovering, and brushing
(https://shiny.rstudio.com/reference/shiny/0.13.1/plotoutput)
It is very similar to your example.
I create a matrix of T/F elements where the rows are the observations and the columns are in which batch the observation is selected. So when you launch the whole matrix is False, but as you click on observations the switch to positive in the first column. Then if you click addSelection and continue you start switching the observations in the next column.
Could you confirm that this what you are looking for?
Below is the code.
shinyApp(
ui = basicPage(
fluidRow(
column(
width = 4,
plotOutput("plot",
height = 300,
click = "plot_click", # Equiv, to click=clickOpts(id='plot_click')
),
actionButton("addToDT", "Add selection", icon = icon("plus")), hr(),
h4("Clicked points"),
tableOutput("plot_clickedpoints"),
),
column(
width = 4,
verbatimTextOutput("counter"),
),
)
),
server = function(input, output, session) {
data <- reactive({
input$newplot
# Add a little noise to the cars data so the points move
cars + rnorm(nrow(cars))
})
output$plot <- renderPlot({
d <- data()
plot(d$speed, d$dist, main = paste("No of Sets Chosen", input$addToDT))
})
output$plot_clickinfo <- renderPrint({
cat("Click:
")
str(input$plot_click)
})
selectedPoints <- reactiveVal(rep(FALSE, nrow(cars)))
selectionMatrix <- reactiveVal(matrix(data = F, nrow = nrow(cars), ncol = 7))
observeEvent(input$plot_click, {
clicked <- nearPoints(data(), input$plot_click, "speed", "dist", allRows = TRUE)$selected
selectedPoints(clicked | selectedPoints())
tmp <- unlist(selectionMatrix())
tmp[, (input$addToDT + 1)] <- selectedPoints()
selectionMatrix(tmp)
})
observeEvent(input$addToDT, {
selectedPoints(rep(FALSE, nrow(cars)))
})
output$plot_clickedpoints <- renderTable({
# if (input$addToDT==0) {
res <- selectionMatrix()
return(res)
})
}
)

How to include sliderInput as label for pie()

I was wondering if it is possible to use the value from a sliderInput() as label for a chart. I tried to build it using reactive() but instead of displaying the value as label is displays a bunch of text (see reproducible example as included below).
Any hints how to solve are much appreciated.
library(shiny)
PT <- c(0.5, 0.5)
label1 <- c(data, 5)
label2 <- c(0, 0)
ui <- fluidPage(
fluidRow(column(width=6, plotOutput("P1", width = "30vw")), column(width = 6, plotOutput("P2", width = "30vw"))),
sliderInput("S1", label = NULL, min = 0, max = 10, value = 5)
)
server <- function(input, output) {
data <- reactive({ c(input$S1) })
output$P1 <- renderPlot({
pie(PT, labels = label1, init.angle = 90)
})
output$P2 <- renderPlot({
pie(PT, labels = label2, init.angle = 90)
})
}
shinyApp(ui = ui, server = server)
Try this
output$P1 <- renderPlot({
label1 <- c(input$S1, 5)
pie(PT, labels = label1, init.angle = 90)
})

Show modal onclick plotly bar plot

I want a pop-up when I click over the bar chart for plotly.
library(shiny)
library(shinymaterial)
df1 <- data.frame(x = 1:10, y = 1:10)
df2 <- data.frame(x = c(rep('a', 10), rep('b', 10)),
y = c(rnorm(10), rnorm(10, 3, 1)))
ui <- material_page(title = "Material Design",
tags$br(),
font_color = "cyan darken-5",
nav_bar_color = "cyan darken-5",
plotlyOutput('scatter')
)
server <- function(input, output) {
output$scatter <- renderPlotly({
plot_ly(df1, x = df1$x, y = df1$y, type = 'bar', source = 'scatter')
})
}
shinyApp(ui = ui, server = server)
I am struck at a point where I need a help; I want a pop-up when I click
over the bar chart the respective contents to be displayed.
Please help me on the same.
You can use an observer and the event_data from your scatterchart to accomplish that. Working example below, hope this helps!
library(shiny)
library(plotly)
df1 <- data.frame(x = 1:10, y = 1:10)
df2 <- data.frame(x = c(rep('a', 10), rep('b', 10)),
y = c(rnorm(10), rnorm(10, 3, 1)))
ui <- fluidPage(
plotlyOutput('scatter')
)
server <- function(input, output) {
output$scatter <- renderPlotly({
plot_ly(df1, x = df1$x, y = df1$y, type = 'bar', source = 'scatter')
})
observeEvent(event_data("plotly_click", source = "scatter"),
{
event_data = event_data("plotly_click", source = "scatter")
showModal(modalDialog(
title = "Important message",
paste0('x: ', event_data$x, ', y: ', event_data$y)
))
}
)
}
shinyApp(ui = ui, server = server)

R Shiny: relayout plotly annotations

I want a plotly plot to change an annotation if the user clicks a button in a shiny app.
I have no idea why this does not work:
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
plot_ly(d)%>%
add_lines(y=d$y, x= d$x)%>%
layout(annotations = list(x = 2, y= 99 , text = "hi"))})
observeEvent(input$button, {
plotlyProxy("plot", session= shiny::getDefaultReactiveDomain()) %>%
plotlyProxyInvoke("relayout", list(annotations= list(x = 2, y= 99 ,
text = "ho")))})}
shinyApp(ui, server)
That is not the way to use relayout in plotly. See below for your example using relayout.
I prefer using native shiny buttons for this purpose because of the greater flexibility it offers. Here is how one might go about achieving the hi-ho toggle.
shiny way
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
p <- plot_ly(d)%>%
add_lines(y=d$y, x= d$x)
if (is.null(input$button) | (input$button%%2 == 0)) {
p <- p %>% layout(annotations = list(x = 2, y= 99 , text = "hi"))
} else {
p <- p %>% layout(annotations = list(x = 2, y= 99 , text = "ho"))
}
p
})
}
shinyApp(ui, server)
In this case though, it is simple enough to make the relayout feature work, although it does require an extra button.
plotly relayout way
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot")
)
server <- function(input, output) {
output$plot <- renderPlotly({
updatemenus <- list(
list(
active = -1,
type = 'buttons',
buttons = list(
list(
label = "hi",
method = "relayout",
args = list(list(annotations = list(list(x = 2, y= 99 , text = "hi"))))),
list(
label = "ho",
method = "relayout",
args = list(list(annotations = list(list(x = 2, y= 99 , text = "ho")))))
)
)
)
p <- plot_ly(d) %>%
add_lines(y=d$y, x= d$x) %>%
layout(updatemenus = updatemenus)
p
})
}
shinyApp(ui, server)
I believe all that needs to change in your code in order to get this to work is wrapping another list around the defined annotation list in your plotly proxy relayout code. I recently discovered that this recursive list structure is all that's needed in order to manipulate annotations using relayout - you can check out my answer to another SO question related to the same issue, but with slightly different context: https://stackoverflow.com/a/70610374/17852464
library(shiny)
library(plotly)
d <- data.frame(x = c(1,2,3), y = c(9,99,999))
ui <- fluidPage(
plotlyOutput("plot"),
actionButton("button", "toggle visibility"))
server <- function(input, output) {
output$plot <- renderPlotly({
plot_ly(d)%>%
add_lines(y=d$y, x= d$x)%>%
layout(annotations = list(x = 2, y= 99 , text = "hi"))
})
observeEvent(input$button, {
plotlyProxy("plot", session= shiny::getDefaultReactiveDomain()) %>%
plotlyProxyInvoke("relayout", list(annotations= list(list(x = 2, y= 99 ,
text = "ho"))))})}
}
shinyApp(ui, server)

Interactive plot in Shiny with rhandsontable and reactiveValues

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})

Resources