I have an Rmarkdown with a simple scatter plot (a map for instance), and I would like users to be able to provide some arbitrary x
and y
coordinates via an input and have those plotted on the graph (in red in the example below). The problem is, I don't have a shiny server so I cannot rely on that option. Is there a implement this, for instance, via javascript or something?
This is what I have:
---
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)
```
This is what I am looking for:
Edit
The example above is a simplification. In reality, the grid is 360x240 and the coordinates can only be integers.
Edit 2 @JohanRosa already provided a nice answer by rebuilding the plot entirely on plotly.js. However, my ggplot is in fact quite complexe and I have many of them. It would therefore be quite complicated for me to rebuild each of them into plotly.js. This is the reason I am looking for an solution that can work directly on the ggplot(ly) that I have.
We can use htmlwidgets::onRender
to inject custom JS code into your ggplotly object.
I reused @JohanRosa's inputs (thanks! +1) and provided an id to the container div to listen on the inputs. Furthermore I'm using Plotly.restyle to avoid redrawing the plot.
Please check the following:
---
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)
```
For additional infos please see chapter 5 "Event handling in JavaScript" from Carson Sievert's book Interactive web-based data visualization with R, plotly, and shiny.