Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.Rと、内部動作を司る server.Rの二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。
RjpWiKiより引用
UI のレイアウトを変えるとツールチップの表示がズレる!
ブログ記事 [1]で、プロットされたデータ点にマウスのポインタを近づけると、データ点に関係する情報をツールチップで表示する、という機能が実装できて喜んだのも束の間、問題を出ました。
ツールチップを表示した例(参考サイト [1])
レイアウトを変えてプロットの上にウィジェットを配置すると、ツールチップが表示される位置がとんでもなくズレてしまうのです(下図)。
レイアウトを変えてツールチップを表示した例
改良版
マウスのポインタの座標を取得する仕組みを理解できておらず、どのようにすれば解決できるのかが皆目判らなかったので、とにかく他の方々がどのようにツールチップを表示させているのかをインターネットで探し続けると、参考サイト [2]にヒントがありました。
ui.Rを下記に示しました。プロットを表示するブロックに、CSS のスタイル position: relative;を加えることでズレを解消できました。
リスト:ui.R
fluidPage(
fluidRow(
titlePanel("Iris explorer"),
selectInput(
inputId = "varX",
label = "Select the X variable",
choices = get.choices()),
selectInput(
inputId = "varY",
label = "Select the Y variable",
choices = get.choices(), selected = 2)
),
hr(),
fluidRow(
style = "position: relative;",
plotOutput(
outputId = "plot",
dblclick = "plot_dblclick",
brush = brushOpts(
id = "plot_brush",
resetOnNew = TRUE
),
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")
),
uiOutput("hover_info")
)
)
server.Rを下記に示しました(参考サイト [1]と同じ)。
リスト:server.R
function(input, output) {
ranges <- reactiveValues(x = NULL, y = NULL)
var.x <- reactive(iris[, as.numeric(input$varX)])
var.y <- reactive(iris[, as.numeric(input$varY)])
label.x <- reactive(names(iris[as.numeric(input$varX)]))
label.y <- reactive(names(iris[as.numeric(input$varY)]))
output$plot <- renderPlot({
ggplot(iris, aes(x = var.x(), y = var.y(), colour = Species)) +
xlab(label.x()) + ylab(label.y()) +
coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = FALSE) +
geom_point(size = 4) + gtheme
})
observeEvent(input$plot_dblclick, {
brush <- input$plot_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- NULL
ranges$y <- NULL
}
})
output$hover_info <- renderUI({
hover <- input$plot_hover
point <- nearPoints(iris, hover, xvar = label.x(), yvar = label.y(), threshold = 5, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
wellPanel(
style = get.style(hover),
p(HTML(paste0("<b> Species: </b>", point$Species, "<br/>",
"<b>", label.x(), ": </b>", point[, label.x()], "<br/>",
"<b>", label.y(), ": </b>", point[, label.y()], "<br/>")))
)
})
}
global.Rを下記に示しました(参考サイト [1]と同じ)。
リスト:global.R
library(shiny)
library(ggplot2)
gtheme <- theme(
axis.title = element_text(size = 16),
axis.text = element_text(size = 16),
axis.line = element_line(),
legend.title = element_text(size = 14),
legend.text = element_text(size = 14),
panel.grid.major = element_line(colour="grey",size = rel(0.5)),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = "whitesmoke")
)
get.choices <- function() {
part.iris <- list()
for (item in names(iris)) {
if (item != "Species") {
part.iris[[item]] <- grep(item, names(iris))
}
}
return(part.iris)
}
get.left_px <- function(hover) {
left_pct <- (hover$x - hover$domain$left) / (hover$domain$right - hover$domain$left)
left_px <- hover$range$left + left_pct * (hover$range$right - hover$range$left)
return(left_px)
}
get.top_px <- function(hover) {
top_pct <- (hover$domain$top - hover$y) / (hover$domain$top - hover$domain$bottom)
top_px <- hover$range$top + top_pct * (hover$range$bottom - hover$range$top)
return(top_px)
}
get.style <- function(hover) {
style <- paste0("position: absolute; z-index: 100; ",
"left:", get.left_px(hover) + 2, "px; ",
"top:", get.top_px(hover) + 2, "px; ",
"background-color: rgba(245, 245, 245, 0.75); ",
"font-family: monospace;")
return(style)
}
下記に実行例を示しました。
ツールチップを表示した例(改良版)
無事解決できましたが、正直、なんとなくコツをつかめたというレベルです。
参考サイト
- bitWalk's: R Shiny のプロットにツールチップを表示する [2019-10-10]
- Shiny でマウスの位置に応じてプロットにツールチップを表示する | Atusy's blog [2019-08-06]
