Измените одну точку на графике scatter3d в R блестящий

1

У меня есть приложение, где я пытаюсь изменить размер точки или цвет или символ. Точка - это объект, который пользователь нажал. Щелчок по точке создает всплывающее окно в моей программе, которое показывает другой набор данных, связанный с идентификационным значением в столбце, принадлежащем роутеру, принадлежащему точке, нажатой. Я включил поток событий в демонстрационное приложение (без всплывающих окон) для события click.

Я пытаюсь изменить точку, основанную на ответе здесь, на сюжетный 2D-график. Однако применение кода к моему 3D-сюжету, похоже, не работает.

Немного дополнительной справочной информации: я создаю программу для анализа данных 3D-рассеяния, и мое приложение содержит несколько этих трехмерных графиков

Кто-нибудь знает, как сделать эту работу?

В приведенном ниже приложении содержится код как для объекта с 2-мя (комментариями), так и для трехмерного изображения, чтобы показать рабочую и нерабочую ситуацию и является прямой модификацией кода, данным @Maximilian Peters

Спасибо за любую помощь!

бонусный вопрос: предположим, что мы можем заставить его работать для 3dplot, я также хотел бы выяснить, как изменить код JavaScript, чтобы изменить точку на основе числа, хранящегося в реактивной переменной (то есть значения $ activepoint), а не щелчка, так как я разрешу пользователю циклически перебирать точки с помощью кнопки <- и ->, которая изменяет идентификатор точки, с которой мы извлекаем дополнительную информацию.

library(shiny)
library(plotly)
library(htmlwidgets)

ui <- fluidPage(
  plotlyOutput("plot"),
  textOutput('messageNr')
)

javascript <- "
function(el, x){
el.on('plotly_click', function(data) {
colors = [];
var base_color = document.getElementsByClassName('legendpoints')[data.points[0].curveNumber].getElementsByTagName('path')[0].style['stroke']
for (var i = 0; i < data.points[0].data.x.length; i += 1) {
colors.push(base_color)
};
colors[data.points[0].pointNumber] = '#000000';
Plotly.restyle(el, 
{'marker':{color: colors}}, 
[data.points[0].curveNumber]
);
//make sure all the other traces get back their original color
for (i = 0; i < document.getElementsByClassName('plotly')[0].data.length; i += 1) {
if (i != data.points[0].curveNumber) {
colors = [];
base_color = document.getElementsByClassName('legendpoints')[i].getElementsByTagName('path')[0].style['stroke'];
for (var p = 0; p < document.getElementsByClassName('plotly')[0].data[i].x.length; p += 1) {
colors.push(base_color);
}
Plotly.restyle(el, 
{'marker':{color: colors}}, 
[i]);
}
};
});
}"


server <- function(input, output, session) {
  row.names(mtcars) <- 1:nrow(mtcars)
  colorscale <- c("blue", "red", "yellow")

  values <- reactiveValues()

  output$plot <- renderPlotly({
    values$point <- event_data("plotly_click", source = "select")

  plot_ly(mtcars,
          x = ~mpg,
          y = ~cyl,
          z = ~wt,
          type = "scatter3d",
          color = as.factor(mtcars$gear),
          colors = colorscale,
          mode = "markers",
          source = "select",
          showlegend = F)%>%
    add_markers() %>% onRender(javascript)
  } )



observeEvent(values$point, {
  values$row <- as.numeric(values$point$pointNumber) +1
   values$ID <- rownames(mtcars)[values$row]
   ### the values$ID is what I use to look up the corresponding dataset in other dataframes containing the detailed info of a datapoint in the 
   ### summary data set that is used to create the real scatter3d plots in which the user clicks. 
  output$messageNr <- renderText(values$ID)
  })
 }

# server <- function(input, output, session) {
# 
#   nms <- row.names(mtcars)
# 
#   output$plot <- renderPlotly({
#     p <- ggplot(mtcars, aes(x = mpg, y = wt, col = as.factor(cyl))) +
#       geom_point()
#     ggplotly(p) %>% onRender(javascript)
# 
#   })
# }

shinyApp(ui, server)
  • 0
    Если кто-то думает, что он может помочь с этим, возможно, мы можем поговорить в чате, чтобы я мог лучше объяснить, чего я пытаюсь достичь
Теги:
shiny
plotly

1 ответ

3
Лучший ответ

Вы можете добавить трассировку только для выделения точки, изменить местоположение одной точки в ответ на Javascript eventListener.

library(shiny)
library(plotly)
library(htmlwidgets)

ui <- fluidPage(
  plotlyOutput("plot"),
  textOutput('messageNr')
)

javascript <- "
function(el, x) {
  el.on('plotly_click', function(data) {

    var highlight_trace = el.data.length - 1;
    //the coordinates of the point which was clicked on
    //is found in data
    var newPoint = {x: data.points[0].x,
                    y: data.points[0].y,
                    z: data.points[0].z};

    //update the plot data and redraw it
    if (el.data[highlight_trace].x[0] != newPoint.x ||
        el.data[highlight_trace].y[0] != newPoint.y ||
        el.data[highlight_trace].z[0] != newPoint.z) {
      el.data[highlight_trace].x[0] = newPoint.x;
      el.data[highlight_trace].y[0] = newPoint.y      
      el.data[highlight_trace].z[0] = newPoint.z
      Plotly.redraw(el);
      }
  })
}
"


server <- function(input, output, session) {

  output$plot <- renderPlotly(
    {
      p <- plot_ly()
      p <- add_trace(p,
              data = mtcars,
              x = ~mpg,
              y = ~cyl,
              z = ~wt,
              color = as.factor(mtcars$gear),
              type = 'scatter3d',
              mode = "markers")
      p <- add_trace(p, 
                     x = c(20), 
                     y = c(5), 
                     z = c(4), 
                     name = 'highlight',
                     type = 'scatter3d',
                     mode = 'markers',
                     marker = list(size = 15,
                                   opacity = 0.5)) %>% onRender(javascript)
      p
    } 
  )
}

shinyApp(ui, server)
  • el - это элемент JavaScript, в котором хранится ваш сюжет
  • "el.data" - это где Plotly хранит данные для вашего участка
  • блок if гарантирует, что график только перерисовывается, если нажимается новая точка
  • если нажимается точка, данные для выделенной трассы перезаписываются и график redraw n

Заметки

  • Убедитесь, что вы используете последнюю версию Plotly, иначе событие click может не работать или работает неправильно.
  • В исходном коде трассировка рисуется несколько раз (удалите showlegend чтобы увидеть ее), возможно, из-за add_markers()

Пример интерактивного JavaScript

Plotly.d3.csv('https://raw.githubusercontent.com/plotly/datasets/master/3d-scatter.csv', function(err, rows) {
      function unpack(rows, key) {
        return rows.map(function(row) {
          return row[key];
        });
      }
      var trace1 = {
        x: unpack(rows, 'x1').slice(0, 30),
        y: unpack(rows, 'y1').slice(0, 30),
        z: unpack(rows, 'z1').slice(0, 30),
        mode: 'markers',
        marker: {
          size: 12,
          line: {
            color: 'rgba(217, 217, 217, 0.14)',
            width: 0.5
          },
          opacity: 0.8
        },
        type: 'scatter3d'
      };

      var trace3 = {
        x: [0],
        y: [0],
        z: [0],
        name: 'highlight',
        mode: 'markers',
        type: 'scatter3d',
        marker: {
          size: 24,
          opacity: 0.5
        }
      };
      var data = [trace1, trace3];
      var layout = {
        margin: {
          l: 0,
          r: 0,
          b: 0,
          t: 0
        }
      };
      
      myDiv = document.getElementById('myDiv');
      Plotly.newPlot(myDiv, data);

      myDiv.on('plotly_click', function(data) {
        var highlight_trace = myDiv.data.length - 1;
        //the coordinates of the point which was clicked on
        //is found in data
        var newPoint = {
          x: data.points[0].x,
          y: data.points[0].y,
          z: data.points[0].z
        };

        //update the plot data and redraw it
        if (myDiv.data[highlight_trace].x[0] != newPoint.x ||
          myDiv.data[highlight_trace].y[0] != newPoint.y ||
          myDiv.data[highlight_trace].z[0] != newPoint.z) {
          myDiv.data[highlight_trace].x[0] = newPoint.x;
          myDiv.data[highlight_trace].y[0] = newPoint.y
          myDiv.data[highlight_trace].z[0] = newPoint.z
          Plotly.redraw(myDiv);
        }
      });


    })
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id='myDiv'></div>
  • 0
    Максимилиан, абсолютно потрясающий, и так мало строк кода! Я собираюсь протестировать его сейчас на графике 10 тыс. Пунктов (мои реальные наборы данных). Один маленький дополнительный вопрос: я не вижу в коде, что определяет размер, форму или цвет выделенного шара с первого взгляда .... но подождите, теперь я понимаю, все это установлено в add_trace, который используется для «имитировать» эффект выделения, рисуя копию нажатой точки. Прекрасный! дал бы +10 за это, если бы я мог
  • 0
    Хорошо, добавил информацию, мне удалось присвоить точке add_trace определенный цвет. Вместо того, чтобы использовать colors = c ('..... colors here'), как в основной трассировке, мне удалось сделать это, добавив "color = 'black' внутри секции marker = list (....) add_trace

Ещё вопросы

Сообщество Overcoder
Наверх
Меню