[英]Tooltip inserting image and/or ggplot in plotly R
我想在 plotly 中創建的 3D UMAP 中編輯工具提示 hover 功能。 What I want to do is attach a saved image corresponding to a specific 'Sample.Code' and have that image appear when I hover over it in the 3D plotly scatter plot.
這將類似於此鏈接中附加的交互式 t-SNE/MNIST 數據集: https://dash.plotly.com/dash-core-components/tooltip
但是,上面寫的是 python 而不是 R。 是否有可能在 R 中實現這一點?
我在下面附上了我的代碼:
# load ggplot2
library(ggplot2)
library(hrbrthemes)
library(tidyverse)
library(dplyr)
library(wesanderson)
library(RColorBrewer)
library(manipulate)
library(umap)
library(plotly)
library(shiny)
library(leaflet)
#set wd to location where plots will be saved. First step is to upload the initial data.
dt <- read.csv('data.csv')
#Run to the UMAP
df <- as.matrix(dt[, 2:149]) #remember to only set columns which will be used in the UMAP calculation
custom.config = umap.defaults #manual settings
custom.config$n_components = 3
custom.config$n_neighbors = 8
custom.config$min_dist = 0.6
data_umap <-umap(df, config = custom.config)
data_raw<-as.data.frame(data_umap$layout)
data_plot <- cbind(data_raw, dt)
#running graphics script. Make sure to change color and size to appropriate labels
#This is the visual that will get manipulated playing around with the UMAP parameters
UMAP_plot <- ggplot(data_plot, aes(x = V1, y = V3, color = Dataset)) +
labs(title = '2D UMAP') +
geom_point(alpha = 0.7, shape =19 ) +
theme_light() +
theme(axis.text.y = element_text(size = 15),
axis.text.x = element_text(size = 10),
axis.title = element_text(size = 15),
plot.title = element_text(size = 17),
legend.text = element_text(size=15)) +
scale_radius(range=c(4, 10))
colors <- c('#4AC6B7', '#1972A4', '#965F8A', '#FF7070', 'darkolivegreen')
UMAP_2D <- plot_ly(data_plot, x= ~V1, y= ~V3, color = ~Dataset, colors=colors, type = "scatter", mode = "markers", text = ~paste('Sample.Code:', Sample.Code))
UMAP_3D <- plot_ly(data_plot, x= ~V1, y= ~V2, z= ~V3, type="scatter3d", mode="markers", color = ~Dataset, colors=colors, text = ~paste('Sample.Code:', Sample.Code))
UMAP_3D <- UMAP_3D %>% layout(title = '3D UMAP',
paper_bgcolor = 'grey',
plot_bgcolor = 'black')
UMAP_3D.update_layout(legend=dict(
yanchor="top",
y=0.99,
xanchor="left",
x=0.01
))
#Eventually add fingerprints to hover based on this code here: https://anchormen.nl/blog/data-science-ai/images-in-plotly-with-r/
print(UMAP_plot)
print(UMAP_2D)
print(UMAP_3D)
根據您的評論,我絕對可以使用 Plotly 示例中的數據。 我還沒有購買 Dash,但您當然可以這樣做並讓自己更輕松。 (我想。我沒用過;所以我猜。)
在沒有 Dash 的情況下,使用 Python 示例,我基本上用 Plotly 在 R 中重新創建了該圖。 我沒有使用ggplot。
我使用了兩個庫,但我唯一一次使用htmlwidgets
時附加了庫名稱。
首先,數據是從與 Python 示例中相同的位置收集的,但我只使用了前 100 行。 接下來,我將換行標記添加到描述中。 SVG 文本中沒有字符串換行。 每行都單獨標記。 我用了 65 個字符,給出或接受一個完整的單詞。 您可以根據您要查找的工具提示的大小對其進行修改。
之后,我創建了基本的 plot。 我將我可以添加的所有內容都添加到了工具提示中,因此我只需要進行一些調整。 Plotly 將所有內容呈現為工具提示中的文本,因此我添加了幾個換行符 (18),以便為圖像留出空間。 我還在工具提示中添加了一些樣式(例如"darkblue"
文本)。
在 JS( htmlwidgets::onRender
中的所有內容)中,您需要收集工具提示中的內容,刪除沒有文本的換行符,並 retrofit 將圖像 URL 作為<image>
元素。
這需要獲得職位和可用空間。 這需要確定工具提示是否在點的左側、點的右側,或者文本是否在工具提示中居中。 對於有擴展描述的點,事情是不對的,所以也需要一些調整。 我在 JS 中添加了很多注釋,所以這也應該解釋很多代碼的目的。
如果您有任何問題,請告訴我。
library(plotly)
# get molecular data
dp <- read.csv("https://raw.githubusercontent.com/plotly/dash-sample-apps/main/apps/dash-drug-discovery/data/small_molecule_drugbank.csv")
# because even SVG doesn't string wrap, each row is a separate tag
dp$desc <- gsub('(.{1,65})(\\s|$)', '\\1<br>', dp$DESC)
plt <- plot_ly(
dp[1:100, ], x = ~LOGP, y = ~PKA, mode = "markers", type = "scatter",
marker = list(colorscale = "Viridis",
color = ~MW, size = ~MW,
colorbar = list(title = "Molecule<br>Weight",
outlinewidth = 0), # just looks better without you!
line = list(color = "#444"),
reversescale = T, sizeref = 45,
sizemode = "diameter", opacity = .8),
customdata = ~IMG_URL,
text = ~NAME, hovertext = ~desc,
hovertemplate = paste0( # 'here' is used for regex in JS
"image href='%{customdata}' here ", # 18 <br> make space for image (see in JS where 18 matters)
"<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>",
"<span style='fill:darkblue;font-size:2em;'>%{text}</span><br>",
"<span>%{hovertext}</span><extra></extra>")) %>%
layout(xaxis = list(title = "Log P"), yaxis = list(title = "pkA"),
plot_bgcolor = "#1a1a1a", paper_bgcolor = "#0d0d0d", # almost and off black
hoverdistance = 10) %>% # more precision in selection
htmlwidgets::onRender("function(el){
console.log(el);
setInterval(function(){ /* no content when tip is called; keep looking */
tt = document.querySelector('#' + el.id + '> div > div > svg:nth-child(5) > g');
},100);
el.on('plotly_hover', function(d){
if(tt.firstChild) {
cvy = parseFloat(getComputedStyle(tt).fontSize); /* em to px conversion */
str = tt.innerHTML;
gimme = /image.*(?=( here \\<br))/.exec(str); /* extract image details */
x = /(?<=(data-notex=\"1\" x=\")).*(?=(\" y=.*data))/g.exec(str);/* image x */
y = /(?<=(y=\")).*(?=(\" data-unformatted))/g.exec(str); /* image y */
bc = tt.getBoundingClientRect();
wbc = bc.width;
hbc = bc.height;
if(/-/.exec(x[0])) wwbc = (wbc * -1) - Number(x[0]); /* adjust x if tip to the left */
if(/-/.exec(x[0]) === null) wwbc = Number(x[0]); /* adjust x if tip to the right */
if(x[0] == 0) wwbc = wbc * -.5; /* if text is centered */
ts = str.match(/\\<tspan?.*?\\/tspan\\>/gm); /* all tspans indexed */
dy = /(?<=(dy=\")).*(?=( x=))/g.exec(ts[18]); /* 18th break in the template (18 br's coded) */
dyc = /.*(?=(em))/.exec(dy[0]); /* collect digits; remove units */
cdy = cvy * Number(dyc[0]); /* convert em to px for image ht */
if(cdy > hbc * .75) cdy = hbc * .65; /* if em => px is larger than plot, reduce */
wbcw = wbc - Math.abs(Number(x[0]) * 2); /* get width for image */
if(ts.length >= 34) {
y[0] = Number(y[0]) * 1.1; /* lots of text images are low & too large */
cdy = cdy * .9;
}
beg = str.match(/.*(?=(\\<text))/); /* everything up to text tags */
jn = '\\<' + gimme[0] + ' x=\"' + wwbc + '\" y=\"' + y[0]; /* the image; can't crtl aspect ratio——Plotly-ism? */
jn = jn + '\" height=\"' + cdy + '\" width=\"' + wbcw +'\"\\/\\>';
tx = str.match(/\\<text.*pre\\;\"\\>?/); /* text element before tspan */
nts = ts.slice(18, ts.length).join('\\<\\/tspan\\>'); /* reassemble kept tspans */
clt = '\\<\\/text\\>\\<\\/g\\>'; /* closing tags */
altog = beg[0] + jn + tx[0] + nts + clt; /* put it together */
tt.innerHTML = altog; /* replace tooltip */
}
});
}")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.