Подсказка к заголовку оси графика

Я хочу иметь всплывающую подсказку на заголовке оси сюжетной графики.

Вот моя попытка:

x <- y <- 1:10
dat <- expand.grid(x=x, y=y)
dat <- transform(dat, z=x*y)

jscode <- '
$(document).ready(function(){
  setTimeout(function(){
    $($("#heatmap .g-xtitle text")[0]).attr("title", "hello").attr("data-toggle", "tooltip");
  }, 5000);
})
'

library(shiny)
library(plotly)
shinyApp(
  ui <- fluidPage(
    tags$head(tags$script(jscode)),
    plotlyOutput("heatmap")
  ),
  server = function(input, output){
    output$heatmap <- renderPlotly(plot_ly() %>%
      add_trace(data=dat, x=~x, y=~y, z=~z, type="heatmap") %>%
      layout(
        xaxis = list(title="foo") 
      )
    )
  }
)

Код JS, как и ожидалось, устанавливает атрибуты data-toggle и title в контейнер заголовка оси X, но всплывающая подсказка не появляется. Я также пробовал что-то вроде $($("#heatmap .g-xtitle text")[0]).tooltip() в консоли, но ничего не происходит.


person Stéphane Laurent    schedule 18.10.2017    source источник


Ответы (2)


Я думаю, что есть пара проблем с вашим кодом:

  1. Сюжету не нравится, что код SVG отредактирован. Даже если вы нацелились на правильный элемент, Plotly, вероятно, сразу удалил то, что вы добавили.
  2. Вам не хватало кода, включающего всплывающие подсказки для приложений.

Я столкнулся с очень похожей проблемой, когда хотел разместить всплывающие подсказки на метках галочек. Мне потребовалось довольно много времени, чтобы взломать его с помощью пользовательских CSS и JS. Идея состоит в том, чтобы добавить div (прямоугольник), который идеально перекрывает элемент, который вы хотите обогатить всплывающей подсказкой. Затем вы устанавливаете CSS opacity этого прямоугольника равным 0, чтобы скрыть его. Но всплывающая подсказка на этом прямоугольнике работает, когда вы наводите на него курсор (даже если он невидим). Вот код, визуализирующий формы прямоугольников.

x <- y <- 1:10
dat <- expand.grid(x = x, y = y)
dat <- transform(dat, z = x * y)

jscode <- "
$(document).ready(function() {
    // Enable tooltips app-wise
    $(\"[data-toggle='tooltip']\").tooltip({container: 'body'}); 
});
"

csscode <- HTML('
    .plot-container {
        position: relative;
    }
    .xaxis-container {
        height: 20px;
        position:absolute;
        bottom: 0;
        left: 40px;
        background: #bfb9b9;
        opacity: 0.3;
    }
    .xaxis-tooltip {
        width: 30px;
        height: 20px;
        background: #000;
        margin:auto;
    }
')

library(shiny)
library(plotly)
shinyApp(
    ui <- fluidPage(
        tags$head(
            tags$script(jscode),
            tags$style(csscode)
        ),
        div(class = 'plot-container',
            plotlyOutput("heatmap"),
            div(
                class = "xaxis-container",
                div(class = "xaxis-tooltip", "data-toggle" = "tooltip", "title" = "hello")
            )
        )
    ),
    server = function(input, output) {
        output$heatmap <- renderPlotly({
            plot_ly() %>%
                add_trace(
                    data = dat,
                    x =  ~ x,
                    y =  ~ y,
                    z =  ~ z,
                    type = "heatmap"
                ) %>%
                layout(xaxis = list(title = "foo")) %>%
                # We can't just center the rectangle relative to the entire plot area.
                # Instead, we need to do it relative to the draglayer.
                # This code sets proper width of .xaxis-container on app start.
                htmlwidgets::onRender(
                    "
                    function(el, x) {
                        var width = $('.draglayer')[0].getBoundingClientRect().width;
                        $('.xaxis-container').css('width', width);
                    }
                    "
                )
        })
    }
)

Измените opacity: 0.3; на opacity: 0; в строке 21, чтобы получить полностью работающее решение.

person Mikolaj    schedule 14.03.2018
comment
Я не пытался понять ваш код, только проверил его. Оно работает. Хорошая работа, и спасибо! - person Stéphane Laurent; 15.03.2018

Примечание. К сожалению, я не решил вашу проблему, но, надеюсь, эта информация окажется полезной. Удачи!

Фон: SVG

  1. plotly создает графики в виде масштабируемой векторной графики (<svg>)

  2. всплывающие подсказки для <svg> должны быть добавлены как дочерний элемент с именем <title>

  3. <title> должен быть первым дочерним элементом своего родителя.

  4. новые элементы <svg> должны быть созданными в пространстве имен SVG

Подсказка SVG: прямоугольник и график по оси X

В качестве доказательства концепции я добавил к вашему примеру прямоугольник <svg>. Затем с помощью JS я добавил элемент <title> в качестве первого дочернего элемента элемента <rect>, который создает всплывающую подсказку на прямоугольнике.

Подсказка прямоугольника svg

Однако выполнение тех же шагов для тепловой карты plotly не приводит к появлению всплывающей подсказки в заголовке по оси X, хотя элемент <title> добавляется в контейнер заголовка по оси X.

svg всплывающая подсказка

Код

library(shiny)
library(plotly)

x <- y <- 1:10
dat <- expand.grid(x=x, y=y)
dat <- transform(dat, z=x*y)

### Create a <svg> rectangle element
testRect <- '<svg width="250" height="75" xmlns="http://www.w3.org/2000/svg">
                <g class="test-rect">
                    <rect x="10" y="10" width="200" height="50" 
                        style="fill:wheat; stroke:blue; stroke-width:1px"/>
                </g>
            </svg>'

### Add a first child title element to the rectangle <svg>
### Hovering over the rectangle displays the tooltip
jscode_testRect <- '$(document).ready(function(){
    setTimeout(function(){
        var titleRect = document.createElementNS("http://www.w3.org/2000/svg", "title");
        titleRect.textContent = "rectangle tooltip";
        var testRect = document.getElementsByClassName("test-rect")[0];
        testRect.insertBefore(titleRect, testRect.childNodes[0]); 
    }, 500);
});'

### Add a first child title element to the SVG
### Hovering over the x-axis title doesn't display tooltip
jscode_xaxisPlotly <- '$(document).ready(function(){
    setTimeout(function(){
        var titleAxis = document.createElementNS("http://www.w3.org/2000/svg", "title");
        titleAxis.textContent = "x-axis tooltip";
        var gXtitle = document.getElementsByClassName("g-xtitle")[0];
        gXtitle.insertBefore(titleAxis, gXtitle.childNodes[0]); 
    }, 500);
});'

shinyApp(
    ui <- fluidPage(
        tags$head(tags$script(HTML(jscode_testRect))),
        tags$head(tags$script(HTML(jscode_xaxisPlotly))),
        h4("<svg> rectangle - tooltip is functional"),
        tags$div(HTML(testRect)),
        h4("plotly heatmap - tooltip does not work"),
        plotlyOutput("heatmap"),
        br(),
        br()
    ),
    server = function(input, output){
        output$heatmap <- renderPlotly(plot_ly() %>%
                                           add_trace(data=dat, x=~x, y=~y, z=~z, type="heatmap") %>%
                                           layout(
                                               xaxis = list(title="foo"),
                                               title = "Title"
                                           )
        )
    }
)
person Hallie Swan    schedule 28.10.2017