您基本上可以在 Shiny 中做几乎任何事情,因为您可以创建自己的输入和输出绑定 - 所以您的问题的答案是肯定的,您所问的都是可能的。假设您有一个数据框,您将其发送到网页以供用户查看。例如,如果某个单元格是应删除的异常值(替换为NA
),您希望允许用户简单地单击该单元格。
假设数据框如下所示:
x <- data.frame(Age = c(10, 20, 1000), Weight = c(120, 131, 111))
x
# Age Weight
# 10 120
# 20 131
# 1000 111
从闪亮你会构建一个普通的 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>
现在打破 jQuery 并绑定一个单击事件,以便在单击单元格时可以记录行号和列号(请参见此处),然后用NA
Shiny 替换该单元格。您的输入绑定可能看起来像(有关此处发生的详细信息,请参见此处):
$(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);
这里发生了很多事情,但通常这些输入绑定彼此非常相似。最重要的是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.
# ...
# ...
})
您可能还需要为 output$outliers 进行输出绑定。这显然是简化的代码,您需要应用错误检查等。
这只是一个例子。实际上,您可能不会在每次用户进行更改时都让 Shiny 更新您的数据框。您可能希望有某种提交按钮,这样一旦用户完成了所有更改,就可以应用它们。
我什至没有远程测试过这些,所以几乎可以肯定有一些错误。但是由于您只是在问一个理论问题,因此我没有过多地检查它。无论如何,一般策略都应该奏效。使用输入绑定,您可以将任何内容从网页返回到服务器,反之亦然,使用输出绑定。也许说“任何事情”有点牵强——但你可以做很多事情。