How do I create an editable table to allow user input, draw scatterplot, and fit a curve through those points?

I am relatively new to Shiny, and currently struggling at putting together a simple Shiny app that does the following job:

  1. Have a table with 10 rows and 2 columns (x and y). The table is blank at initiation, and is completely user editable through using library(DT). All the data points are through user inputs. Let's restrict x and y to be only positive numbers.

  2. Have a graph on the right side (or at bottom). Once user finishes inputting 20 values in the table (10 x values & 10 y values), click on an actionbutton, and the graph will ** draw a scatterplot ** using those 10 sets of value points, and fit a line through those points.

  3. If the user wants to make any edits to the table, he/she edits the table directly, and click on the actionbutton again to re-draw a new scatterplot, and re-fit a line.

I am struggling at how to make the user inputs in the table into the inputs of that scatterplot and eventually fit a line through. This task is unlike my previous work, where I only have to build an interactive shiny app using data from an existing dataset (e.g. read a csv).

Much appreciation for your help!

Here's an app I created quickly that I believe fits your requirements, this article was helpful in the editing piece.

library(shiny)
library(DT)
library(tidyverse)

ui <- fluidPage(

    # Application title
    titlePanel("Editable Dataframe and Plot"),

    # Sidebar
    sidebarLayout(
        sidebarPanel(
            DTOutput("my_datatable"),
            actionButton("go",label = "Plot Data")
        ),

        # Show plot
        mainPanel(
           plotOutput("my_plot")
        )
    )
)

server <- function(input, output) {
    
    #initialize a blank dataframe
    v <- reactiveValues(data = { 
        data.frame(x = numeric(0),y = numeric(0)) %>% 
            add_row(x = rep(0,10),y = rep(0,10))
    })

    #output the datatable based on the dataframe (and make it editable)
    output$my_datatable <- renderDT({
        DT::datatable(v$data, editable = TRUE)
    })
    
    #when there is any edit to a cell, write that edit to the initial dataframe
    #check to make sure it's positive, if not convert
    observeEvent(input$my_datatable_cell_edit, {
        #get values
        info = input$my_datatable_cell_edit
        i = as.numeric(info$row)
        j = as.numeric(info$col)
        k = as.numeric(info$value)
        if(k < 0){ #convert to positive if negative
            k <- k * -1
        }
        
        #write values to reactive
        v$data[i,j] <- k
    })
    
    #render plot
    output$my_plot <- renderPlot({
        req(input$go) #require the input button to be non-0 (ie: don't load the plot when the app first loads)
        isolate(v$data) %>%  #don't react to any changes in the data
            ggplot(aes(x,y)) +
            geom_point() +
            geom_smooth(method = "lm")
    })
    
}

# Run the application 
shinyApp(ui = ui, server = server)
5 Likes

Hi Ben,

Thanks so much! This is EXACTLY what I am looking for.

Your code does exactly what I am looking for, and your detailed comments help me understand the flow of reactivity in certain parts of the server. The article you linked is very helpful as well.

Thanks!

1 Like

This topic was automatically closed 7 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.