Поместите диаграмму в всплывающее окно plotly
Я использую plotly для R, хотя я также открыт для использования версии Python. Когда я наведу курсор на точку данных, есть ли способ сделать всплывающее окно содержать другую диаграмму? В идеале диаграмма будет создана из данных, хотя я могу использовать статическое изображение в качестве запасного варианта.
Я не уверен, с чего начать, и заранее извиняюсь за то, что у меня нет MWE.
3 ответов
Решение 1: придерживайтесь R
спасибо @MLavoie. В следующем примере используйте pure R
чтобы создать два сюжета, "mainplot" и "hover", который реагирует на событие наведения первого.
library(shiny)
library(plotly)
ui <- fluidPage(
plotlyOutput("mainplot"),
plotlyOutput("hover")
)
server <- function(input, output) {
output$mainplot <- renderPlotly({
# https://plot.ly/r/
d <- diamonds[sample(nrow(diamonds), 1000), ]
plot_ly(d, x = carat, y = price, text = paste("Clarity: ", clarity), mode = "markers", color = carat, size = carat, source="main")
})
output$hover <- renderPlotly({
eventdat <- event_data('plotly_hover', source="main") # get event data from source main
if(is.null(eventdat) == T) return(NULL) # If NULL dont do anything
point <- as.numeric(eventdat[['pointNumber']]) # Index of the data point being charted
# draw plot according to the point number on hover
plot_ly( x = c(1,2,3), y = c(point, point*2, point*3), mode = "scatter")
})
}
shinyApp(ui, server)
в этом примере использовать shiny binds for plotly
. для каждого события наведения a POST
запрос отправляется на сервер, затем сервер обновит всплывающую диаграмму. Это очень неэффективно, поэтому может не работать хорошо на медленном подключение.
приведенный выше код предназначен только для демонстрации и еще не протестирован. См. рабочий и гораздо более сложный пример здесь (С источник).
Решение 2: Javascript
Да, вы можете сделать это с помощью плотный Javascript API.
короткий ответ:
- создайте свой график с помощью
R
илиPython
или любой другой поддерживаемый язык. - вставить график в новую HTML-страницу и добавить функцию обратного вызова, как показано в примере ниже. Если у вас есть хорошие знания о дом, вы также можете добавить JS в исходный HTML вместо создания нового.
- нарисуйте всплывающий график внутри функции обратного вызова,которая принимает параметры, содержащие данные точки данных при наведении.
подробности
Как упоминалось в @MLavoie, показан хороший пример в plotly.Ховер-события
давайте покопаемся в коде. В js-файле есть простая функция обратного вызова, прикрепленная к Plot
:
Plot.onHover = function(message) {
var artist = message.points[0].x.toLowerCase().replace(/ /g, '-');
var imgSrc = blankImg;
if(artistToUrl[artist] !== undefined) imgSrc = artistToUrl[artist];
Plot.hoverImg.src = imgSrc;
};
выше artistToUrl
- огромный объект, заполненный строкой base64, которую я не буду вставлять здесь, чтобы переполнить сообщение. Но вы можете увидеть его на вкладке JS страницы примера. Он имеет такую структуру:
var artistToUrl = { 'bob-dylan': 'data:image/jpeg;base64,/...',...}
пример:
для демонстрации, я готовлю простой пример здесь (щелкните, чтобы попробовать):
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<iframe id="plot" style="width: 900px; height: 600px;" src="https://plot.ly/~jackp/10816.embed" seamless></iframe>
<div id="myDiv"></div>
<script>
(function main() {
var Plot = { id: 'plot', domain: 'https://plot.ly' };
Plot.onHover = function(message) {
var y = message.points[0].y; /*** y value of the data point(bar) under hover ***/
var line1 = {
x: [0.25,0.5,1], /*** dummy x array in popup-chart ***/
y: [1/y, 2, y], /*** dummy y array in popup-chart ***/
mode: 'lines+markers'
};
var layout = {
title:'Popup graph on hover',
height: 400,
width: 480
};
Plotly.newPlot('myDiv', [ line1 ], layout); // this finally draws your popup-chart
};
Plot.init = function init() {
var pinger = setInterval(function() {
Plot.post({task: 'ping'});
}, 500);
function messageListener(e) {
var message = e.data;
if(message.pong) {
console.log('Initial pong, frame is ready to receive');
clearInterval(pinger);
Plot.post({
'task': 'listen',
'events': ['hover']
});
}
else if(message.type === 'hover') {
Plot.onHover(message);
}
}
window.removeEventListener('message', messageListener);
window.addEventListener('message', messageListener);
};
Plot.post = function post(o) {
document.getElementById(Plot.id).contentWindow.postMessage(o, Plot.domain);
};
Plot.init();
})();
</script>
</body>
</html>
- это доработанная от poltly.Ховер-события пример для python. Вместо попиных изображение, изменить onhover
обратный вызов для построения кривой на основе y
значение каждого бара.
основная диаграмма генерируется python и вставляется здесь как iframe
. Вы можете сделать свой собственный на любом языке, включая R
. На этой странице мы добавляем <div id="myDiv"></div>
и используйте plotly.js для рисования popup-chart whithin it.
экспорт кадра данных R в JS enviornment
блестящие использует jsonlite преобразование R
объекты json
и отправить их клиенту. Мы можем использовать тот же механизм для упаковки и отправки фрейма данных, чтобы обратный вызов JS мог использовать данные для отображения всплывающей диаграммы.
сервер.r
output$json <- reactive({
paste('<script>data =', RJSONIO::toJSON(your_data_frame, byrow=T, colNames=T),'</script>')
пользовательский интерфейс.r
fluidPage(..., htmlOutput("json"), ...)
в функции обратного вызова JS вы можете использовать data
как и любой другой JS объекты.
если вы хотите придерживаться с R
можно использовать Shiny
получить почти нужный результат. При наведении указателя мыши на каждую точку изображение будет отображаться под основным сюжетом. В приведенном ниже примере я использовал первые три строки mtcars
наборы данных. Чтобы запустить код, вам нужно только 3 логотипа / изображения, соответствующие названию первых трех строк (под mtcars$name
, Mazda RX4
, Mazda RX4 Wag
, Datsun 710
в этом примере).
library(shiny)
library(plotly)
datatest <- diamonds %>% count(cut)
datatest$ImageNumber <- c(0, 1, 2, 3, 4)
datatest$name <- c("Image0", "Image1", "Image2", "Image3", "Image4")
ui <- fluidPage(
plotlyOutput("plot"),
# verbatimTextOutput("hover2"),
#imageOutput("hover"),
plotlyOutput("hover3")
)
server <- function(input, output, session) {
output$plot <- renderPlotly({
plot_ly(datatest, x = cut, y = n, type = "bar", marker = list(color = toRGB("black")))
})
selected_image <- reactive({
eventdat <- event_data('plotly_hover', source = 'A')
ImagePick <- as.numeric(eventdat[['pointNumber']])
sub <- datatest[datatest$ImageNumber %in% ImagePick, ]
return(sub)
})
# output$hover2 <- renderPrint({
#d <- event_data("plotly_hover")
#if (is.null(d)) "Hover events appear here (unhover to clear)" else d
#})
# output$hover <- renderImage({
# datag <- selected_image()
#filename <- normalizePath(file.path('/Users/drisk/Desktop/temp',
# paste(datag$name, '.png', sep='')))
# Return a list containing the filename and alt text
# list(src = filename,
# alt = paste("Image number", datag$name))
# }, deleteFile = FALSE)
output$hover3 <- renderPlotly({
datag <- selected_image()
# draw plot according to the point number on hover
plot_ly(data=datag, x = ImageNumber, y = n, mode = "scatter")
})
}
shinyApp(ui, server)
кажется, ответы, опубликованные не работают для вас @Adam_G. Я изучал подобные библиотеки для своей собственной работы и определил, что Plot.ly
не всегда правильный путь, когда вы хотите дополнительных функций. Вы видели bokeh
? Он в основном предназначен для этого типа задач и намного проще в реализации (также D3.библиотеку JS, как Plot.ly
). Вот копия примера, который они опубликовали, где вы можете переместить ползунок, чтобы изменить график данных (аналогично примеру, опубликованному @gdlmx для Сюжет.ly, но вы можете использовать его без размещения на веб-сайте). Я добавил flexx
пакет, чтобы вы могли использовать этот чистый Python (без JavaScript-он может переводить функции Python на JavaScript (CustomJS.from_py_func(callback)
) https://github.com/zoofIO/flexx-notebooks/blob/master/flexx_tutorial_pyscript.ipynb):
from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import figure, output_file, show
import flexx
output_file("callback.html")
x = [x*0.005 for x in range(0, 200)]
y = x
source = ColumnDataSource(data=dict(x=x, y=y))
plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
def callback(source=source):
data = source.get('data')
f = cb_obj.get('value') #this is the bokeh callback object, linked to the slider below
x, y = data['x'], data['y']
for i in range(len(x)):
y[i] = x[i]**f #the slider value passed to this function as f will alter chart as a function of x and y
source.trigger('change') #as the slider moves, the chart will change
slider = Slider(start=0.1, end=4, value=1, step=.1, title="power", callback=CustomJS.from_py_func(callback))
layout = vform(slider, plot)
show(layout)
см. здесь фактический пример в действии: http://bokeh.pydata.org/en/0.10.0/docs/user_guide/interaction.html#customjs-for-widgets
для интеграции с событиями наведения см. здесь (from bokeh.models import HoverTool
):
http://bokeh.pydata.org/en/0.10.0/docs/user_guide/interaction.html#customjs-for-hover
наведите пример:
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models import HoverTool
output_file("toolbar.html")
source = ColumnDataSource(
data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
desc=['A', 'b', 'C', 'd', 'E'],
)
)
hover = HoverTool(
tooltips=[
("index", "$index"),
("(x,y)", "($x, $y)"),
("desc", "@desc"),
]
)
p = figure(plot_width=400, plot_height=400, tools=[hover], title="Mouse over the dots")
p.circle('x', 'y', size=20, source=source)
show(p)
глядя на 1-й код, вы можете поместить любую формулу, которую хотите под - где требуется. Вы можете получить наведение на измените график рядом с ним (hform(leftchart, rightchart)
или над / под ним (vform(topchart, bottomchart)
). Это передается как CustomJS
, который bokeh
использует для расширения и flexx
позволяет писать его на Python.
альтернатива заключается в том, чтобы поместить все, что вы хотите настроить на hover tooltips
использование HTML (хотя этот пример помещает изображения в словари вместо новых графиков из базовых данных): http://bokeh.pydata.org/en/0.10.0/docs/user_guide/tools.html#custom-tooltip