Блестящий обновите нажатую точку, чтобы выделить ее

Вот рабочий пример извлечения события по щелчку. Я хотел бы спросить вас, есть ли способ обновить точку, в которой щелкнули, либо увеличив ее размер, либо выделив ее и т. Д.,?

library(shiny)
library(plotly)

ui <- fluidPage(
    plotlyOutput("plot"),
    verbatimTextOutput("click")
)

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

    nms <- row.names(mtcars)

    output$plot <- renderPlotly({
        p <- ggplot(mtcars, aes(x = mpg, y = wt, col = as.factor(cyl), key = nms)) + 
           geom_point()
        ggplotly(p)

    })

    output$click <- renderPrint({
        d <- event_data("plotly_click")
        if (is.null(d)) "Click events appear here (double-click to clear)" 
        else cat("Selected point associated with Car: ", d$key)
    })

}

shinyApp(ui, server)

введите описание изображения здесь

Я провел поиск в SO и других подходящих источниках, чтобы найти решение приведенного ниже вопроса, но не нашел его.

Обновление:

  • Это решение лучше подходит для этого игрушечного сюжета. Но мой исходный вариант использования содержит 50+ уровней для интересующей переменной, и есть высокая вероятность того, что пурпурный или любой другой цвет уже будет присутствовать. Кроме того, на изменение цвета уходит много времени.
  • Есть ли способ увеличить размер нажатой точки, чтобы отличить ее от сотен ближайших точек?

Связанный вопрос об изменении формы точки, на которой щелкнули мышью, был задан здесь.


person Prradep    schedule 30.08.2017    source источник
comment
Есть потенциально связанный с этим вопрос (блестящие динамические слои ggplot с помощью nearPoints ()), который не связан с plotly.   -  person Uwe    schedule 31.08.2017
comment
@Uwe Спасибо, я разберусь. Одно главное наблюдение: nearPoints() не работает в случае ggplotly графиков. Во-вторых, поскольку весь график снова строится, может возникнуть мнение, что уровни факторов получат новые цвета, и будет трудно идентифицировать выбранную область на всем графике.   -  person Prradep    schedule 31.08.2017


Ответы (1)


Вы можете добавить события Plotly в свое приложение Shiny с помощью функции htmlwidget onrender.

ggplotly(p) %>% onRender(javascript)

Массив colors передается функции restyle. Выбранная точка (pointNumber) окрашена в пурпурный цвет, а остальные - в цвет из легенды. Вы можете сделать то же самое с размером marker, символ маркера немного сложнее, потому что Plotly не принимает здесь массивы.

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] = '#FF00FF';
    Plotly.restyle(el, 
                   {'marker':{color: colors}}, 
                   [data.points[0].curveNumber]
                  );

  });
}

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

ui <- fluidPage(
  plotlyOutput("plot")
)

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] = '#FF00FF';
    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) {

  nms <- row.names(mtcars)

  output$plot <- renderPlotly({
    p <- ggplot(mtcars, aes(x = mpg, y = wt, col = as.factor(cyl), key = nms)) + 
      geom_point()
    ggplotly(p) %>% onRender(javascript)

  })
}

shinyApp(ui, server)

Некоторые пояснения:

  • События Plotly, например plotly_click передать некоторую информацию (data в данном случае) в функцию события
  • data.points содержит точки, для которых событие было инициировано
  • в этом случае у нас есть только одна точка data.points[0], где pointNumber - это индекс исходного массива, а curveNumber - номер трассировки.
  • Графически сохраняет все входные данные в div, где строится график.
  • Мы можем получить к нему доступ через document.getElementsByClassName('plotly')[0].data
  • Доступ к легенде можно получить через document.getElementsByClassName('legendpoints')[i], где i - это индекс легенды.
  • ggplotly или plot_ly возвращают htmlwidgets
  • Код Javascript или HTML можно добавить с помощью любой из функций htmlwidget, например onrender в этом случае
person Maximilian Peters    schedule 30.08.2017
comment
Спасибо. Работает блестяще (+1). В моем первоначальном варианте использования переменная содержит более 50 уровней, и очень высока вероятность, что magenta будет одним из них. В таком случае будет сложно идентифицировать выбранную точку. Вы думаете о других вариантах? (Небольшая опечатка в вашем ответе plotlyOutput("plot"), запятой быть не должно). - person Prradep; 31.08.2017
comment
Спасибо, что нашли остатки редактирования кода! Вы также можете изменить размер, например sizes.push(10);... sizes[...pointNumber] = 20;... 'marker': {size: sizes} - person Maximilian Peters; 31.08.2017
comment
(Забыл задать еще один вопрос, который я имел в виду) Почему я могу выделить точку для каждого уровня фактора? На приведенном выше графике я могу выделить максимум три точки (каждая из которых принадлежит cyl==4, cyl==6, cyl==8). Я хотел бы выделить максимум одну точку на точку, прежде чем она исчезнет, ​​чтобы выделить следующую точку щелчка. Что ты думаешь? - person Prradep; 31.08.2017
comment
Правильный способ сделать это - изменить стиль всех следов / факторов. В примере рестайлинг только след от точки щелчка, я добавил недостающий код в пример. - person Maximilian Peters; 31.08.2017
comment
Не могли бы вы указать мне источники, откуда я могу понять ваш код и развить намеченные вами направления? Я хотел бы посмотреть, какие еще компоненты можно извлечь и как их можно изменить. Спасибо! - person Prradep; 31.08.2017
comment
Прошу прощения, но, за исключением ссылки в ответе, в основном это был метод проб и ошибок, а также обратный инжиниринг. Подробной документации не так много. - person Maximilian Peters; 31.08.2017
comment
Давайте продолжим это обсуждение в чате. - person Prradep; 31.08.2017
comment
@Prradep, пожалуйста, примите этот ответ, нажав на галочку слева от ответа. - person CPak; 31.08.2017
comment
@MaximilianPeters У меня есть дополнительный вопрос, но для ясности я сделал новый пост SO. Это включает в себя настройку вашего фантастического ответа для работы с объектами scatter3d plotly. Его можно найти здесь: https://stackoverflow.com/questions/47365402/shiny-highlight-a-point-in-plotly-scatter3d - person Mark; 18.11.2017
comment
@MaximilianPeters, мне не удалось ответить на ваш вопрос, основанный на графике для построения графиков. Я только что изменил раздел сервера следующим образом: plot_ly(x = c(1,2,3,4,5)) %>% add_bars( y = c(1,2,2.5,4,5), marker = list(color=c(rep('red',5)))) %>% onRender(javascript). Остальная часть такая же. Не могли бы вы сообщить мне, что мне не хватает. - person olcaysah; 29.09.2018