Shiny R应用程序,允许用户修改数据

dev*_*mag 21 r shiny shiny-server

这不是一个实际问题,而是一个理论问题.我正在考虑使用Shiny以交互方式显示一些原始数据.这可以.

但是 - 是否可以让用户更改显示的数据?

比方说,如果我有一堆滑块供用户限制基础数据以满足某些条件并显示这些观察结果 - 是否可以允许用户对该数据进行修改并将这些修改发送回服务器,反过来又保存了这些变化?

我在考虑用户可以使用Shiny Application浏览数据并检测数据中潜在异常值的情况 - 然后用户可以将这些标记为异常值.但是,该信息需要传递回服务器.

这样的申请可能吗?是否有一些现有的例子?

Mad*_*one 19

你基本上可以在Shiny中做任何事情,因为你可以创建自己的输入输出绑定 - 所以你的问题的答案是肯定的,你所要求的是可能的.假设您有一个数据框,您发送到网页以供用户查看.例如,您希望允许用户只需单击一个单元格,如果它是一个应该删除的异常值(替换为NA).

假设数据框看起来像这样:

x <- data.frame(Age = c(10, 20, 1000), Weight = c(120, 131, 111))
x

# Age    Weight
# 10     120
# 20     131
# 1000   111
Run Code Online (Sandbox Code Playgroud)

从闪亮中你可以构建一个普通的HTML表格,在网页上显示时可能看起来像这样:

 <table class="outlier-finder" id="outliers">
  <tr>
    <td>Age</td>
    <td>Weight</td>
  </tr>
  <tr>
    <td>10</td>
    <td>120</td>
  </tr>
  <tr>
    <td>20</td>
    <td>131</td>
  </tr>
  <tr>
    <td>1000</td>
    <td>111</td>
  </tr>
</table>
Run Code Online (Sandbox Code Playgroud)

现在打破jQuery并绑定一个click事件,这样当单击一个单元格时,你可以记录行号和列号(见这里),然后用NAShiny 替换那个单元格.您的输入绑定可能看起来像(有关此处发生的详细信息,请参见此处):

$(document).on("click", ".outlier-finder td", function(evt) {

  // Identify the clicked cell.
  var el = $(evt.target);

  // Raise an event to signal that the something has been selected.
  el.trigger("change");

});

var cell_binding = new Shiny.InputBinding();

$.extend(cell_binding, {

  find: function(scope) {
    return $(scope).find(".outlier-finder td");
  },

  getValue: function(el) {
    // Get the row and cell number of the selected td.
    var col = el.parent().children().index(el);
    var row = el.parent().parent().children().index(el.parent());
    var result = [row, col];
    return result;
  },

  setValue: function(el, value) {
    $(el).text(value);
  },

  subscribe: function(el, callback) {
    $(el).on("change.cell_binding", function(e) {
      callback();
    });
  },

  unsubscribe: function(el) {
    $(el).off(".cell_binding");
  }

});

Shiny.inputBindings.register(cell_binding);
Run Code Online (Sandbox Code Playgroud)

这里有很多内容,但通常这些输入绑定彼此非常相似.最重要的是setValue()功能.那里应该发生什么(这是未经测试的)是被记录的单元格的行号和列号被记录并发回服务器.

然后从Shiny你只需要做一些事情:

updateData <- reactive({

    # Get selection
    remove_outlier <- as.integer(RJSONIO::fromJSON(input$outliers))

    if (!is.null(remove_outlier)) {

      # Remove that outlier.
      x[remove_outlier[1], remove_outlier[2]] <- NA

    }

    return(x)

})

output$outliers <- renderText({

  # Update x.
  current_x <- updateData()

  # Write code to output current_x to page.
  # ... 
  # ...

})
Run Code Online (Sandbox Code Playgroud)

您可能还需要为输出$ outliers进行输出绑定.这显然是简化代码,您需要应用错误检查等.

这只是一个例子.实际上,每次用户进行更改时,您可能不会使Shiny更新数据框.您可能希望拥有某种提交按钮,以便一旦用户完成所有他/她的更改,就可以应用它们.


我甚至没有远程测试任何这些,所以几乎肯定有一些错误.但既然你只是在问一个理论问题,我就没有检查过多.无论如何,一般的策略应该是有效的.使用输入绑定,您可以通过输出绑定从网页返回到服务器,反之亦然.也许说"任何事情"都是一个延伸 - 但你可以做很多事情.