Hello everyone,
I'm trying to create a very simple game in R Shiny, but I don't know how to get started. I'm looking for a bit of skeleton code to figure out how the game loop will work, so I can modify that for my own needs. Specifically, what I'm looking for is the code for a Shiny app with a single PlotOutput ggplot object, with a plot title that is a number; it starts at 0 and goes up by 1 every time the user clicks on the plot. I think if I have this basic structure, I can expand it to fit my own needs.
Thank you!
There you go (added a little theming):
library(shiny)
library(bslib)
library(bsicons)
library(thematic)
library(datasets)
library(ggplot2)
ui <- page_navbar(
theme = bs_theme(version = 5, bootswatch = bootswatch_themes()[1L]),
nav_spacer(),
nav_panel(
title = "Home",
icon = bs_icon("house"),
plotOutput("plot", click = "plot_click")
),
nav_panel(
title = "Empty page",
icon = bs_icon("database"),
tags$p('Empty page')
),
title = "Test"
)
server <- function(input, output, session) {
thematic_shiny()
output$plot <- renderPlot({
ggplot(mtcars, aes(wt, mpg)) + geom_point() + ggtitle(nclicks()) +
theme(plot.title = element_text(hjust = 0.5))
}, res = 96L)
nclicks <- reactiveVal(0L)
observeEvent(input$plot_click, {
nclicks(nclicks()+1L)
})
}
shinyApp(ui = ui, server = server)
Not sure if this is an option for you, but I'd suggest to use {plotly} instead of {ggplot2} because plot_ly()
or ggplot
objects can be modified via plotlyProxy
. The ggplot output is re-rendered after every click, which is slow.
Thank you! What would the equivalent code in plotly look like? I'm not familiar with that package. Performance is a big concern for me, since it's a game.
Do you need the click event everywhere on the plot element or only on specified datapoints?
Everywhere on the plot, if possible!
This is an example based on my answer here :
library(plotly)
library(shiny)
library(htmlwidgets)
initDF <- data.frame(x = 1:10, y = 1:10)
ui <- fluidPage(
plotlyOutput("myPlot"),
verbatimTextOutput("click")
)
server <- function(input, output, session) {
js <- "
function(el, x, inputName){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
var d3 = Plotly.d3;
Plotly.update(id).then(attach);
function attach() {
gd.addEventListener('click', function(evt) {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var bb = evt.target.getBoundingClientRect();
var x = xaxis.p2d(evt.clientX - bb.left);
var y = yaxis.p2d(evt.clientY - bb.top);
var coordinates = [x, y];
Shiny.setInputValue(inputName, coordinates, {priority: 'event'});
});
};
}
"
clickposition_history <- reactiveVal(initDF)
observeEvent(input$clickposition, {
clickposition_history(rbind(clickposition_history(), input$clickposition))
})
output$myPlot <- renderPlotly({
plot_ly(initDF, x = ~x, y = ~y, type = "scatter", mode = "markers") |> layout(title = "nclicks: 0")|>
onRender(js, data = "clickposition")
})
myPlotProxy <- plotlyProxy("myPlot", session)
observe({
plotlyProxyInvoke(myPlotProxy, "restyle", list(x = list(clickposition_history()$x), y = list(clickposition_history()$y)))
})
output$click <- renderPrint({
clickposition_history()
})
# modify title ------------------------------------------------------------
nclicks <- reactiveVal(0L)
observeEvent(input$clickposition, {
nclicks(nclicks()+1L)
})
observe({
plotlyProxyInvoke(myPlotProxy, "relayout", list(title = paste0("nclicks: ", nclicks())))
})
}
shinyApp(ui, server)
For clicks on the datapoints we could have used plotly::event_data()
instead of custom JS.
Also check this:
system
Closed
March 9, 2024, 2:56pm
7
This topic was automatically closed 54 days after the last reply. New replies are no longer allowed. If you have a query related to it or one of the replies, start a new topic and refer back with a link.