Tengo un Rmarkdown con un diagrama de dispersión simple (un mapa, por ejemplo), y me gustaría que los usuarios puedan proporcionar algunas coordenadas x e y arbitrarias a través de una entrada y tenerlas trazadas en el gráfico (en rojo en el ejemplo a continuación) . El problema es que no tengo un servidor brillante, así que no puedo confiar en esa opción. ¿Hay alguna implementación de esto, por ejemplo, a través de javascript o algo así?
Esto es lo que tengo:
--- 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) ```Esto es lo que estoy buscando:
Editar
El ejemplo anterior es una simplificación. En realidad, la cuadrícula es de 360x240 y las coordenadas solo pueden ser números enteros.
Edit 2 @JohanRosa ya proporcionó una buena respuesta al reconstruir la trama por completo en plotly.js. Sin embargo, mi ggplot es bastante complejo y tengo muchos de ellos. Por lo tanto, sería bastante complicado para mí reconstruir cada uno de ellos en plotly.js. Esta es la razón por la que estoy buscando una solución que pueda funcionar directamente en el ggplot (ly) que tengo.
Podemos usar htmlwidgets::onRender para inyectar código JS personalizado en su objeto ggplotly.
Reutilicé las entradas de @JohanRosa (¡gracias! +1) y proporcioné una identificación al contenedor div para escuchar las entradas. Además, estoy usando Plotly.restyle para evitar volver a dibujar la trama.
Por favor revisa lo siguiente:
--- 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) ```Para obtener información adicional, consulte el capítulo 5 "Manejo de eventos en JavaScript" del libro de Carson Sievert Visualización interactiva de datos basada en la web con R, plotly y shiny .
Puede que esto no sea lo que quieres, pero puedes hacerlo agregando un tiempo de ejecución de shiny en tu yaml
--- 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')) }) ```Lo hice usando plotlty.js directamente en JavaScript. Creo que con esto puedes avanzar.
--- 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); }) ```