R ggplot 或 plotly 没有闪亮的用户输入
User inputs for R ggplot or plotly without shiny
我有一个带有简单散点图(例如地图)的 Rmarkdown,我希望用户能够通过输入提供一些任意 x
和 y
坐标,并具有绘制在图表上的那些(在下面的示例中以红色显示)。问题是,我没有闪亮的服务器,所以我不能依赖那个选项。是否有一个实现这个,例如,通过 javascript 或其他东西?
这是我的:
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
```
```{r fig.height=4, fig.width=4}
X <- data.frame(x = 1:10, y = 1:10)
gg <- ggplot(X, aes(x, y)) + geom_point()
ggplotly(gg)
```
这就是我要找的:
编辑
上面的例子是一个简化。现实中网格是360x240,坐标只能是整数
编辑 2
@JohanRosa 已经通过完全在 plotly.js 上重建情节提供了一个很好的答案。然而,我的 ggplot 实际上非常复杂,我有很多。因此,将它们中的每一个重建为 plotly.js 对我来说是相当复杂的。这就是我正在寻找可以直接在我拥有的 ggplot(ly) 上工作的解决方案的原因。
这可能不是您想要的,但您可以通过在 yaml 中添加 shiny 运行时来做到这一点
---
title: "Untitled"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
library(shiny)
```
```{r shinyInputs}
shiny::numericInput('someInput', "Some Number", value = 5)
shiny::numericInput('someInput2', "Some Number2", value = 2)
plotlyOutput('gg')
```
```{r fig.height=4, fig.width=4}
X <- data.frame(x = 1:10, y = 1:10)
output$gg <- renderPlotly({
temp <- tibble::tibble(x = input$someInput, y = input$someInput2)
ggplotly(ggplot(X, aes(x, y)) + geom_point() + geom_point(data = temp, aes(x =
x, y = y), color = 'red'))
})
```
我是直接在JavaScript中用plotlty.js做的。我认为有了这个你可以进步。
---
output: html_document
---
<!-- This is a container for your inputs -->
:::{.input-container}
:::{.xs}
### X coordinate
<input type='number' value=5 id='x1' class='x'>
<input type='number' value=2.5 id='x2' class='x'>
<input type='number' value=7.5 id='x3' class='x'>
:::
:::{.ys}
### Y coordinate
<input type='number' value=10 id='y1'>
<input type='number' value=5 id='y2'>
<input type='number' value=2.5 id='y3'>
:::
:::
<!--
I did it using a submit button, I have to read more to make it totally reactive
-->
<input type='button' id='plot' value='Update points' class='btn btn-primary'>
<!-- The next div is a placeholder for the plot -->
<div id="tester" style="width:600px;height:250px;"></div>
<!-- You have to include the plolty.js script -->
<script src="https://cdn.plot.ly/plotly-2.9.0.min.js"></script>
<!-- css configuration to arrange the inputs -->
```{css, echo = FALSE}
input {
display: block;
}
.xs, .ys {
display: inline-block;
}
```
<!-- This is the magic, the Js code -->
<!-- language: lang-js -->
```{js, echo=FALSE}
// Get the html element that should contain the plot
plot = document.getElementById('tester');
// Create an object with the default data
let var1 = {
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
mode: 'markers',
type: 'scatter',
name: 'deafault'
}
let layout = {
xaxis: {
range: [ 0, 10.5 ]
},
yaxis: {
range: [0, 10.5]
},
title:'Testing'
};
let data = [var1]
// Default plot
Plotly.newPlot(plot, data, layout);
// Using jQuery add an event listener on click to de button
// that way when the user click on it the plot will be updated
$('#plot').click(function(){
let userInputs = {
x: [$('#x1').val(), $('#x2').val(), $('#x3').val()],
y: [$('#y1').val(), $('#y2').val(), $('#y3').val()],
mode: 'markers',
type: 'scatter',
name: 'user'
}
data = [var1, userInputs]
Plotly.newPlot(plot, data, layout);
})
```
我们可以使用 htmlwidgets::onRender
将自定义 JS 代码注入到您的 ggplotly 对象中。
我重用了@JohanRosa 的输入(谢谢!+1)并向容器提供了一个 id div 来监听输入。此外,我正在使用 Plotly.restyle 来避免重绘情节。
请检查以下内容:
---
title: "ggplotly user inputs"
output: html_document
---
:::{#inputcontainerid .input-container}
:::{.xs}
### X coordinate
<input type='number' value=5 id='x1' class='x'>
<input type='number' value=2.5 id='x2' class='x'>
<input type='number' value=7.5 id='x3' class='x'>
:::
:::{.ys}
### Y coordinate
<input type='number' value=10 id='y1'>
<input type='number' value=5 id='y2'>
<input type='number' value=2.5 id='y3'>
:::
:::
<!-- css configuration to arrange the inputs -->
```{css, echo = FALSE}
input {
display: block;
}
.xs, .ys {
display: inline-block;
}
```
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
library(htmlwidgets)
```
```{r out.width='100%', echo=FALSE}
X <- data.frame(x = 1:10, y = 1:10)
JS <- "
function(el, x){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
let defaultInputs = {
x: [$('#x1').val(), $('#x2').val(), $('#x3').val()],
y: [$('#y1').val(), $('#y2').val(), $('#y3').val()],
mode: 'markers',
type: 'scatter',
name: 'user'
};
Plotly.addTraces(gd, defaultInputs);
document.getElementById('inputcontainerid').addEventListener('input', function(event){
let userInputs = {
x: [[$('#x1').val(), $('#x2').val(), $('#x3').val()]],
y: [[$('#y1').val(), $('#y2').val(), $('#y3').val()]]
};
Plotly.restyle(gd, userInputs, 1);
});
}
"
gg <- ggplot(X, aes(x, y)) + geom_point()
ggplotly(gg) %>%
layout(xaxis = list(autorange = TRUE), yaxis = list(autorange = TRUE)) %>%
onRender(jsCode = JS)
```
有关其他信息,请参阅 chapter 5 Carson Sievert 的书 Interactive web-based data visualization with R, plotly, and shinychapter 5“JavaScript 中的事件处理”.
我有一个带有简单散点图(例如地图)的 Rmarkdown,我希望用户能够通过输入提供一些任意 x
和 y
坐标,并具有绘制在图表上的那些(在下面的示例中以红色显示)。问题是,我没有闪亮的服务器,所以我不能依赖那个选项。是否有一个实现这个,例如,通过 javascript 或其他东西?
这是我的:
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
```
```{r fig.height=4, fig.width=4}
X <- data.frame(x = 1:10, y = 1:10)
gg <- ggplot(X, aes(x, y)) + geom_point()
ggplotly(gg)
```
这就是我要找的:
编辑
上面的例子是一个简化。现实中网格是360x240,坐标只能是整数
编辑 2 @JohanRosa 已经通过完全在 plotly.js 上重建情节提供了一个很好的答案。然而,我的 ggplot 实际上非常复杂,我有很多。因此,将它们中的每一个重建为 plotly.js 对我来说是相当复杂的。这就是我正在寻找可以直接在我拥有的 ggplot(ly) 上工作的解决方案的原因。
这可能不是您想要的,但您可以通过在 yaml 中添加 shiny 运行时来做到这一点
---
title: "Untitled"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
library(shiny)
```
```{r shinyInputs}
shiny::numericInput('someInput', "Some Number", value = 5)
shiny::numericInput('someInput2', "Some Number2", value = 2)
plotlyOutput('gg')
```
```{r fig.height=4, fig.width=4}
X <- data.frame(x = 1:10, y = 1:10)
output$gg <- renderPlotly({
temp <- tibble::tibble(x = input$someInput, y = input$someInput2)
ggplotly(ggplot(X, aes(x, y)) + geom_point() + geom_point(data = temp, aes(x =
x, y = y), color = 'red'))
})
```
我是直接在JavaScript中用plotlty.js做的。我认为有了这个你可以进步。
---
output: html_document
---
<!-- This is a container for your inputs -->
:::{.input-container}
:::{.xs}
### X coordinate
<input type='number' value=5 id='x1' class='x'>
<input type='number' value=2.5 id='x2' class='x'>
<input type='number' value=7.5 id='x3' class='x'>
:::
:::{.ys}
### Y coordinate
<input type='number' value=10 id='y1'>
<input type='number' value=5 id='y2'>
<input type='number' value=2.5 id='y3'>
:::
:::
<!--
I did it using a submit button, I have to read more to make it totally reactive
-->
<input type='button' id='plot' value='Update points' class='btn btn-primary'>
<!-- The next div is a placeholder for the plot -->
<div id="tester" style="width:600px;height:250px;"></div>
<!-- You have to include the plolty.js script -->
<script src="https://cdn.plot.ly/plotly-2.9.0.min.js"></script>
<!-- css configuration to arrange the inputs -->
```{css, echo = FALSE}
input {
display: block;
}
.xs, .ys {
display: inline-block;
}
```
<!-- This is the magic, the Js code -->
<!-- language: lang-js -->
```{js, echo=FALSE}
// Get the html element that should contain the plot
plot = document.getElementById('tester');
// Create an object with the default data
let var1 = {
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
mode: 'markers',
type: 'scatter',
name: 'deafault'
}
let layout = {
xaxis: {
range: [ 0, 10.5 ]
},
yaxis: {
range: [0, 10.5]
},
title:'Testing'
};
let data = [var1]
// Default plot
Plotly.newPlot(plot, data, layout);
// Using jQuery add an event listener on click to de button
// that way when the user click on it the plot will be updated
$('#plot').click(function(){
let userInputs = {
x: [$('#x1').val(), $('#x2').val(), $('#x3').val()],
y: [$('#y1').val(), $('#y2').val(), $('#y3').val()],
mode: 'markers',
type: 'scatter',
name: 'user'
}
data = [var1, userInputs]
Plotly.newPlot(plot, data, layout);
})
```
我们可以使用 htmlwidgets::onRender
将自定义 JS 代码注入到您的 ggplotly 对象中。
我重用了@JohanRosa 的输入(谢谢!+1)并向容器提供了一个 id div 来监听输入。此外,我正在使用 Plotly.restyle 来避免重绘情节。
请检查以下内容:
---
title: "ggplotly user inputs"
output: html_document
---
:::{#inputcontainerid .input-container}
:::{.xs}
### X coordinate
<input type='number' value=5 id='x1' class='x'>
<input type='number' value=2.5 id='x2' class='x'>
<input type='number' value=7.5 id='x3' class='x'>
:::
:::{.ys}
### Y coordinate
<input type='number' value=10 id='y1'>
<input type='number' value=5 id='y2'>
<input type='number' value=2.5 id='y3'>
:::
:::
<!-- css configuration to arrange the inputs -->
```{css, echo = FALSE}
input {
display: block;
}
.xs, .ys {
display: inline-block;
}
```
```{r setup, include=FALSE}
library(ggplot2)
library(plotly)
library(htmlwidgets)
```
```{r out.width='100%', echo=FALSE}
X <- data.frame(x = 1:10, y = 1:10)
JS <- "
function(el, x){
var id = el.getAttribute('id');
var gd = document.getElementById(id);
let defaultInputs = {
x: [$('#x1').val(), $('#x2').val(), $('#x3').val()],
y: [$('#y1').val(), $('#y2').val(), $('#y3').val()],
mode: 'markers',
type: 'scatter',
name: 'user'
};
Plotly.addTraces(gd, defaultInputs);
document.getElementById('inputcontainerid').addEventListener('input', function(event){
let userInputs = {
x: [[$('#x1').val(), $('#x2').val(), $('#x3').val()]],
y: [[$('#y1').val(), $('#y2').val(), $('#y3').val()]]
};
Plotly.restyle(gd, userInputs, 1);
});
}
"
gg <- ggplot(X, aes(x, y)) + geom_point()
ggplotly(gg) %>%
layout(xaxis = list(autorange = TRUE), yaxis = list(autorange = TRUE)) %>%
onRender(jsCode = JS)
```
有关其他信息,请参阅 chapter 5 Carson Sievert 的书 Interactive web-based data visualization with R, plotly, and shinychapter 5“JavaScript 中的事件处理”.